Filters allow you to apply a range of effects to bitmap and display
objects, ranging from drop shadows to bevels and blurs. Each filter
is defined as a class, so applying filters involves creating instances
of filter objects, which is no different from constructing any other
object. Once you’ve created an instance of a filter object, it can
easily be applied to a display object by using the object’s
filters
property,
or in the case of a BitmapData object, by using the
applyFilter()
method.
Creating a filter
To create a
filter object, simply call the constructor method of your selected
filter class. For example, to create a DropShadowFilter object,
use the following code:
import flash.filters.DropShadowFilter;
var myFilter:DropShadowFilter = new DropShadowFilter();
Although not shown here, the
DropShadowFilter()
constructor
(like all the filter classes’ constructors) accepts several optional
parameters that can be used to customize the appearance of the filter
effect.
Applying a filter
Once you've constructed a filter
object, you can apply it to a display object or a BitmapData object;
how you apply the filter depends on the object to which you’re applying
it.
Applying a filter to a display object
When you apply filter effects
to a display object, you apply them through the
filters
property.
The
filters
property of a display object is an
Array instance, whose elements are the filter objects applied to
the display object. To apply a single filter to a display object,
create the filter instance, add it to an Array instance, and assign
that Array object to the display object’s
filters
property:
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;
If you want
to assign multiple filters to the object, simply add all the filters
to the Array instance before assigning it to the
filters
property.
You can add multiple objects to an Array by passing them as parameters
to its constructor. For example, this code applies a bevel filter
and a glow filter to the previously created display object:
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;
When you’re
creating the array containing the filters, you can create it using
the
new Array()
constructor (as shown in the previous
examples) or you can use Array literal syntax, wrapping the filters
in square brackets (
[]
). For instance, this line
of code:
var filters:Array = new Array(dropShadow, blur);
does
the same thing as this line of code:
var filters:Array = [dropShadow, blur];
If
you apply multiple filters to display objects, they are applied
in a cumulative, sequential manner. For example, if a filters array
has two elements, a bevel filter added first and a drop shadow filter
added second, the drop shadow filter is applied to both the bevel
filter and the display object. This is because of the drop shadow
filter’s second position in the filters array. If you want to apply
filters in a noncumulative manner, apply each filter to a new copy
of the display object.
If you’re only assigning one or a few
filters to a display object, you can create the filter instance
and assign it to the object in a single statement. For example,
the following line of code applies a blur filter to a display object
called
myDisplayObject
:
myDisplayObject.filters = [new BlurFilter()];
The
previous code creates an Array instance using Array literal syntax
(square braces), creates a BlurFilter instance as an element in
the Array, and assigns that Array to the
filters
property
of the display object named
myDisplayObject
.
Removing filters from a display object
Removing all filters from a
display object is as simple as assigning a null value to the
filters
property:
myDisplayObject.filters = null;
If
you’ve applied multiple filters to an object and want to remove
only one of the filters, you must go through several steps to change
the
filters
property array. For more information,
see
Potential issues for working with filters
.
Applying a filter to a BitmapData object
Applying a filter to a
BitmapData object requires the use of the BitmapData object’s
applyFilter()
method:
var rect:Rectangle = new Rectangle();
var origin:Point = new Point();
myBitmapData.applyFilter(sourceBitmapData, rect, origin, new BlurFilter());
The
applyFilter()
method
applies a filter to a source BitmapData object, producing a new,
filtered image. This method does not modify the original source
image; instead, the result of the filter being applied to the source
image is stored in the BitmapData instance on which the
applyFilter()
method
is called.
How filters work
Display
object filtering works by caching a copy of the original object
as a transparent bitmap.
Once a filter has been applied to a display object, the runtime
caches the object as a bitmap for as long as the object has a valid
filter list. This source bitmap is then used as the original image
for all subsequently applied filter effects.
Each display object usually contains two bitmaps: one with the
original unfiltered source display object and another for the final
image after filtering. The final image is used when rendering. As
long as the display object does not change, the final image does
not need updating.
Potential issues for working with filters
There are several potential sources of confusion or trouble to
keep in mind when you’re working with filters.
Filters and bitmap caching
To apply a filter to a display object,
bitmap caching must be enabled for that object. When you apply a
filter to a display object whose
cacheAsBitmap
property
is set to
false
, the object’s
cacheAsBitmap
property
is automatically set to
true
. If you later remove
all the filters from the display object, the
cacheAsBitmap
property
is reset to the last value it was set to.
Changing filters at run time
If a display object already has one
or more filters applied to it, you can’t change the set of filters
by adding additional filters to or removing filters from the
filters
property
array. Instead, to add to or change the set of filters being applied,
you must make your changes to a separate array, then assign that
array to the filters property of the display object for the filters
to be applied to the object. The simplest way to do this is to read
the
filters
property array into an Array variable
and make your modifications to this temporary array. You then reassign
this array back to the
filters
property of the
display object. In more complex cases, you might need to keep a
separate master array of filters. You make any changes to that master
filter array, and reassign the master array to the display object’s
filters
property
after each change.
Adding an additional filter
The following code demonstrates the
process of adding an additional filter to a display object that
already has one or more filters applied to it. Initially, a glow filter
is applied to the display object named
myDisplayObject
;
later, when the display object is clicked, the
addFilters()
function
is called. In this function, two additional filters are applied
to
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);
Removing one filter from a set of filters
If a display object has
multiple filters applied to it, and you want to remove one of the
filters while the other filters continue to be applied to the object,
you copy the filters into a temporary array, remove the unwanted
filter from that array, and reassign the temporary array to the
display object’s
filters
property. Several ways
to remove one or more elements from any array are described in
Retrieving values and removing array elements
.
The most straightforward situation is to
remove the top-most filter on the object (the last filter applied
to the object). You use the Array class’s
pop()
method
to remove the filter from the array:
// 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;
Similarly,
to remove the bottom-most filter (the first one applied to the object) you
use the same code, substituting the Array class’s
shift()
method
in place of the
pop()
method.
To remove a
filter from the middle of an array of filters (assuming that the
array has more than two filters) you can use the
splice()
method.
You must know the index (the position in the array) of the filter
you want to remove. For example, the following code removes the
second filter (the filter at index 1) from a display object:
// 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;
Determining a filter’s index
You need to know which filter to remove
from the array, so that you know the index of the filter. You must
either know (by virtue of the way the application is designed),
or calculate the index of the filter to remove.
The best approach
is to design your application so that the filter you want to remove
is always in the same position in the set of filters. For example,
if you have a single display object with a convolution filter and
a drop-shadow filter applied to it (in that order), and you want
to remove the drop-shadow filter but keep the convolution filter,
the filter is in a known position (the top-most filter) so that
you can know ahead of time which Array method to use (in this case
Array.pop()
to
remove the drop-shadow filter).
If the filter you want to
remove is always a certain type, but not necessarily always in the
same position in the set of filters, you can check the data type
of each filter in the array to determine which one to remove. For
example, the following code determines which of a set of filters
is a glow filter, and removes that filter from the set.
// 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;
In a more complex
case, such as if the filter to remove is selected at runtime, the best
approach is to keep a separate, persistent copy of the filter array
that serves as the master list of filters. Any time you make a change
to the set of filters, change the master list then apply that filter
array as the
filters
property of the display object.
For
example, in the following code listing, multiple convolution filters
are applied to a display object to create different visual effects,
and at a later point in the application one of those filters is
removed while the others are retained. In this case, the code keeps
a master copy of the filters array, as well as a reference to the filter
to remove. Finding and removing the specific filter is similar to
the preceding approach, except that instead of making a temporary
copy of the filters array, the master copy is manipulated and then
applied to the display object.
// 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;
}
In this approach (when you’re comparing a stored
filter reference to the items in the filters array to determine
which filter to remove), you
must
keep a separate copy of
the filters array—the code does not work if you compare the stored
filter reference to the elements in a temporary array copied from
the display object’s
filters
property. This is
because internally, when you assign an array to the
filters
property,
the runtime makes a copy of each filter object in the array. Those
copies (rather than the original objects) are applied to the display
object, and when you read the
filters
property
into a temporary array, the temporary array contains references
to the copied filter objects rather than references to the original
filter objects. Consequently, if in the preceding example you try
to determine the index of
filterToRemove
by comparing
it to the filters in a temporary filters array, no match is found.
Filters and object transformations
No filtered region—a drop shadow,
for example—outside of a display object’s bounding box rectangle
is considered to be part of the surface for the purposes of hit
detection (determining if an instance overlaps or intersects with
another instance). Because the DisplayObject class’s hit detection
methods are vector-based, you cannot perform a hit detection on
the bitmap result. For example, if you apply a bevel filter to a
button instance, hit detection is not available on the beveled portion
of the instance.
Scaling, rotating, and skewing are not supported
by filters; if the filtered display object itself is scaled (if
scaleX
and
scaleY
are
not 100%), the filter effect does not scale with the instance. This
means that the original shape of the instance rotates, scales, or
skews; however, the filter does not rotate, scale, or skew with the
instance.
You can animate an instance with a filter to create
realistic effects, or nest instances and use the BitmapData class
to animate filters to achieve this effect.
Filters and Bitmap objects
When you apply any filter to a BitmapData
object, the
cacheAsBitmap
property is automatically
set to
true
. In this way, the filter is actually
applied to the copy of the object rather than to the original.
This
copy is then placed on the main display (over the original object)
as close as possible to the nearest pixel. If the bounds of the
original bitmap change, the filtered copy bitmap is recreated from
the original, rather than being stretched or distorted.
If
you clear all filters for a display object, the
cacheAsBitmap
property
is reset to what it was before the filter was applied.
|
|
|