The Filter Workbench provides a user interface
to apply different filters to images and other visual content and
see the resulting code that can be used to generate the same effect
in ActionScript. In addition to providing a tool for experimenting with
filters, this application demonstrates the following techniques:
To get the application files for this sample, see
www.adobe.com/go/learn_programmingAS3samples_flash
.
The Filter Workbench application files can be found in the Samples/FilterWorkbench folder.
The application consists of the following files:
File
|
Description
|
com/example/programmingas3/filterWorkbench/FilterWorkbenchController.as
|
Class that provides the main functionality
of the application, including switching content to which filters
are applied, and applying filters to content.
|
com/example/programmingas3/filterWorkbench/IFilterFactory.as
|
Interface defining common methods that are
implemented by each of the filter factory classes. This interface
defines the common functionality that the FilterWorkbenchController
class uses to interact with the individual filter factory classes.
|
in folder com/example/programmingas3/filterWorkbench/:
BevelFactory.as
BlurFactory.as
ColorMatrixFactory.as
ConvolutionFactory.as
DropShadowFactory.as
GlowFactory.as
GradientBevelFactory.as
GradientGlowFactory.as
|
Set of classes, each of which implements
the IFilterFactory interface. Each of these classes provides the functionality
of creating and setting values for a single type of filter. The
filter property panels in the application use these factory classes
to create instances of their particular filters, which the FilterWorkbenchController
class retrieves and applies to the image content.
|
com/example/programmingas3/filterWorkbench/IFilterPanel.as
|
Interface defining common methods that are
implemented by classes that define the user interface panels that
are used to manipulate filter values in the application.
|
com/example/programmingas3/filterWorkbench/ColorStringFormatter.as
|
Utility class that includes a method to
convert a numeric color value to hexadecimal String format
|
com/example/programmingas3/filterWorkbench/GradientColor.as
|
Class that serves as a value object, combining
into a single object the three values (color, alpha, and ratio) that
are associated with each color in the GradientBevelFilter and GradientGlowFilter
|
User
interface (Flex)
|
|
FilterWorkbench.mxml
|
The
main file defining the application’s user interface.
|
flexapp/FilterWorkbench.as
|
Class
that provides the functionality for the main application’s user
interface; this class is used as the code-behind class for the application
MXML file.
|
In
folder flexapp/filterPanels:
BevelPanel.mxml
BlurPanel.mxml
ColorMatrixPanel.mxml
ConvolutionPanel.mxml
DropShadowPanel.mxml
GlowPanel.mxml
GradientBevelPanel.mxml
GradientGlowPanel.mxml
|
Set
of MXML components that provide the functionality for each panel
that is used to set options for a single filter.
|
flexapp/ImageContainer.as
|
A
display object that serves as a container for the loaded image on
the screen
|
flexapp/controls/BGColorCellRenderer.as
|
Custom
cell renderer used to change the background color of a cell in the DataGrid
component
|
flexapp/controls/QualityComboBox.as
|
Custom
control defining a combo box that can be used for the Quality setting in
several filter panels.
|
flexapp/controls/TypeComboBox.as
|
Custom
control defining a combo box that can be used for the Type setting
in several filter panels.
|
User
interface (Flash)
|
|
FilterWorkbench.fla
|
The
main file defining the application’s user interface.
|
flashapp/FilterWorkbench.as
|
Class
that provides the functionality for the main application’s user
interface; this class is used as the document class for the application
FLA file.
|
In
folder flashapp/filterPanels:
BevelPanel.as
BlurPanel.as
ColorMatrixPanel.as
ConvolutionPanel.as
DropShadowPanel.as
GlowPanel.as
GradientBevelPanel.as
GradientGlowPanel.as
|
Set
of classes that provide the functionality for each panel that is
used to set options for a single filter.
For each class, there is also an associated
MovieClip symbol in the library of the main application FLA file,
whose name matches the name of the class (for example, the symbol
“BlurPanel” is linked to the class defined in BlurPanel.as). The
components that make up the user interface are positioned and named
within those symbols.
|
flashapp/ImageContainer.as
|
A
display object that serves as a container for the loaded image on
the screen
|
flashapp/BGColorCellRenderer.as
|
Custom
cell renderer used to change the background color of a cell in the DataGrid
component
|
flashapp/ButtonCellRenderer.as
|
Custom
cell renderer used to include a button component in a cell in the
DataGrid component
|
Filtered image content
|
|
com/example/programmingas3/filterWorkbench/ImageType.as
|
This class serves as a value object containing
the type and URL of a single image file to which the application
can load and apply filters. The class also includes a set of constants
representing the actual image files available.
|
images/sampleAnimation.swf,
images/sampleImage1.jpg,
images/sampleImage2.jpg
|
Images and other visual content to which
filters are applied in the application.
|
Experimenting with ActionScript filters
The Filter Workbench application is designed to help you experiment
with various filter effects and generate the relevant ActionScript
code for that effect. The application lets you select from three
different files containing visual content, including bitmap images
and an animation created by Flash, and apply eight different ActionScript
filters to the selected image, either individually or in combination
with other filters. The application includes the following filters:
-
Bevel (flash.filters.BevelFilter)
-
Blur (flash.filters.BlurFilter)
-
Color matrix (flash.filters.ColorMatrixFilter)
-
Convolution (flash.filters.ConvolutionFilter)
-
Drop shadow (flash.filters.DropShadowFilter)
-
Glow (flash.filters.GlowFilter)
-
Gradient bevel (flash.filters.GradientBevelFilter)
-
Gradient glow (flash.filters.GradientGlowFilter)
Once a user has selected an image and a filter to apply to that
image, the application displays a panel with controls for setting
the specific properties of the selected filter. For example, the
following image shows the application with the Bevel filter selected:
As the user adjusts the filter properties, the preview updates
in real time. The user can also apply multiple filters by customizing
one filter, clicking the Apply button, customizing another filter,
clicking the Apply button, and so forth.
There are a few features and limitations in the application’s
filter panels:
-
The color matrix filter includes a set of controls for
directly manipulating common image properties including brightness,
contrasts, saturation, and hue. In addition, custom color matrix
values can be specified.
-
The convolution filter, which is only available using ActionScript,
includes a set of commonly used convolution matrix values, or custom
values can be specified. However, while the ConvolutionFilter class
accepts a matrix of any size, the Filter Workbench application uses
a fixed 3 x 3 matrix, the most commonly used filter size.
-
The displacement map filter and shader filter, which are
only available in ActionScript, are not available in the Filter
Workbench application.
Creating filter instances
The Filter Workbench application includes a set of classes, one
for each of the available filters, which are used by the individual
panels to create the filters. When a user selects a filter, the
ActionScript code associated with the filter panel creates an instance
of the appropriate filter factory class. (These classes are known
as
factory classes
because their purpose is to create instances
of other objects, much like a real-world factory creates individual
products.)
Whenever the user changes a property value on the panel, the
panel’s code calls the appropriate method in the factory class.
Each factory class includes specific methods that the panel uses
to create the appropriate filter instance. For example, if the user
selects the Blur filter, the application creates a BlurFactory instance.
The BlurFactory class includes a
modifyFilter()
method
that accepts three parameters:
blurX
,
blurY
,
and
quality
, which together are used to create
the desired BlurFilter instance:
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));
}
On the other hand, if the user selects the Convolution filter,
that filter allows for much greater flexibility and consequently
has a larger set of properties to control. In the ConvolutionFactory
class, the following code is called when the user selects a different
value on the filter panel:
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));
}
Notice that in each case, when the filter values are changed,
the factory object dispatches an
Event.CHANGE
event
to notify listeners that the filter’s values have changed. The FilterWorkbenchController
class, which does the work of actually applying filters to the filtered
content, listens for that event to ascertain when it needs to retrieve
a new copy of the filter and re-apply it to the filtered content.
The FilterWorkbenchController class doesn’t need to know specific
details of each filter factory class—it just needs to know that
the filter has changed and to be able to access a copy of the filter.
To support this, the application includes an interface, IFilterFactory,
that defines the behavior a filter factory class needs to provide
so the application’s FilterWorkbenchController instance can do its
job. The IFilterFactory defines the
getFilter
()
method that’s used in the FilterWorkbenchController class:
function getFilter():BitmapFilter;
Notice that the
getFilter()
interface method
definition specifies that it returns a BitmapFilter instance rather
than a specific type of filter. The BitmapFilter class does not
define a specific type of filter. Rather, BitmapFilter is the base class
on which all the filter classes are built. Each filter factory class
defines a specific implementation of the
getFilter()
method
in which it returns a reference to the filter object it has built.
For example, here is an abbreviated version of the ConvolutionFactory
class’s source code:
public class ConvolutionFactory extends EventDispatcher implements IFilterFactory
{
// ------- Private vars -------
private var _filter:ConvolutionFilter;
...
// ------- IFilterFactory implementation -------
public function getFilter():BitmapFilter
{
return _filter;
}
...
}
In the ConvolutionFactory class’s implementation of the
getFilter()
method,
it returns a ConvolutionFilter instance, although any object that
calls
getFilter()
doesn’t necessarily know that—according
to the definition of the
getFilter()
method that
ConvolutionFactory follows, it must return any BitmapFilter instance,
which could be an instance of any of the ActionScript filter classes.
Applying filters to display objects
As explained previously, the Filter Workbench application uses
an instance of the FilterWorkbenchController class (hereafter referred
to as the “controller instance”), which performs the actual task
of applying filters to the selected visual object. Before the controller
instance can apply a filter, it first needs to know what image or
visual content the filter should be applied to. When the user selects
an image, the application calls the
setFilterTarget()
method
in the FilterWorkbenchController class, passing in one of the constants
defined in the ImageType class:
public function setFilterTarget(targetType:ImageType):void
{
...
_loader = new Loader();
...
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, targetLoadComplete);
...
}
Using that information the controller instance loads the designated
file, storing it in an instance variable named
_currentTarget
once
it loads:
private var _currentTarget:DisplayObject;
private function targetLoadComplete(event:Event):void
{
...
_currentTarget = _loader.content;
...
}
When the user selects a filter, the application calls the controller
instance’s
setFilter()
method, giving the controller
a reference to the relevant filter factory object, which it stores
in an instance variable named
_filterFactory
.
private var _filterFactory:IFilterFactory;
public function setFilter(factory:IFilterFactory):void
{
...
_filterFactory = factory;
_filterFactory.addEventListener(Event.CHANGE, filterChange);
}
Notice that, as described previously, the controller instance
doesn’t know the specific data type of the filter factory instance
that it is given; it only knows that the object implements the IFilterFactory
instance, meaning it has a
getFilter()
method and
it dispatches a
change
(
Event.CHANGE
)
event when the filter changes.
When the user changes a filter’s properties in the filter’s panel,
the controller instance finds out that the filter has changed through
the filter factory’s
change
event, which calls
the controller instance’s
filterChange()
method.
That method, in turn, calls the
applyTemporaryFilter()
method:
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();
}
The work of applying the filter to the display object occurs
within the
applyTemporaryFilter()
method. First,
the controller retrieves a reference to the filter object by calling
the filter factory’s
getFilter()
method.
var currentFilter:BitmapFilter = _filterFactory.getFilter();
The controller instance has an Array instance variable named
_currentFilters
,
in which it stores all the filters that have been applied to the
display object. The next step is to add the newly updated filter
to that array:
_currentFilters.push(currentFilter);
Next, the code assigns the array of filters to the display object’s
filters
property,
which actually applies the filters to the image:
_currentTarget.filters = _currentFilters;
Finally, since this most recently added filter is still the “working”
filter, it shouldn’t be permanently applied to the display object,
so it is removed from the
_currentFilters
array:
_currentFilters.pop();
Removing this filter from the array doesn’t affect the filtered
display object, because a display object makes a copy of the filters
array when it is assigned to the
filters
property,
and it uses that internal array rather than the original one. For
this reason, any changes that are made to the array of filters don’t
affect the display object until the array is assigned to the display
object’s
filters
property again.
|
|
|