筛选显示对象示例:Filter Workbench

Flash Player 9 和更高版本,Adobe AIR 1.0 和更高版本

Filter Workbench 提供了一个用户界面,用于对图像和其他可视内容应用不同的滤镜以及查看结果代码,这些代码可用于在 ActionScript 中生成相同的效果。除了提供试验滤镜的工具外,此应用程序还展示了以下技巧:

  • 创建各种滤镜的实例

  • 对显示对象应用多种滤镜

若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn 。可以在 Samples/FilterWorkbench 文件夹中找到 Filter Workbench 应用程序文件。该应用程序包含以下文件:

文件

说明

com/example/programmingas3/filterWorkbench/FilterWorkbenchController.as

提供应用程序主要功能的类,主要功能包括切换要应用滤镜的内容以及将滤镜应用于内容。

com/example/programmingas3/filterWorkbench/IFilterFactory.as

用来定义由各滤镜工厂类所实现的常用方法的接口。此接口定义 FilterWorkbenchController 类用来与各个滤镜工厂类交互的常见功能。

在文件夹 com/example/programmingas3/filterWorkbench/ 中:

BevelFactory.as

BlurFactory.as

ColorMatrixFactory.as

ConvolutionFactory.as

DropShadowFactory.as

GlowFactory.as

GradientBevelFactory.as

GradientGlowFactory.as

类集,每个类都实现 IFilterFactory 接口。每个类均可为某一类型的滤镜提供创建和设置值的功能。应用程序中的滤镜属性面板使用这些工厂类来创建其特定滤镜的实例,FilterWorkbenchController 类将检索这些实例并将它们应用于图像内容。

com/example/programmingas3/filterWorkbench/IFilterPanel.as

定义某些类(这些类定义用于操作应用程序中滤镜值的用户界面面板)所实现的常见方法的接口。

com/example/programmingas3/filterWorkbench/ColorStringFormatter.as

实用程序类,包含将数字颜色值转换为十六进制字符串格式的方法

com/example/programmingas3/filterWorkbench/GradientColor.as

作为值对象的类,此类将与 GradientBevelFilter 和 GradientGlowFilter 中各颜色相关联的三个值(颜色、Alpha 和比例)合并到单个对象中

用户界面 (Flex)

FilterWorkbench.mxml

定义应用程序用户界面的主要文件。

flexapp/FilterWorkbench.as

为主应用程序用户界面提供功能的类;此类用作应用程序 MXML 文件的代码隐藏类。

在 flexapp/filterPanels 文件夹中:

BevelPanel.mxml

BlurPanel.mxml

ColorMatrixPanel.mxml

ConvolutionPanel.mxml

DropShadowPanel.mxml

GlowPanel.mxml

GradientBevelPanel.mxml

GradientGlowPanel.mxml

MXML 组件集,为各面板(用于为单个滤镜设置选项)提供功能。

flexapp/ImageContainer.as

作为屏幕上已加载图像的容器的显示对象

flexapp/controls/BGColorCellRenderer.as

用于更改 DataGrid 组件中单元格的背景颜色的自定义单元格渲染器

flexapp/controls/QualityComboBox.as

自定义控件,负责定义可用于多个滤镜面板中“品质”设置的组合框。

flexapp/controls/TypeComboBox.as

自定义控件,负责定义可用于多个滤镜面板中“类型”设置的组合框。

用户界面 (Flash)

FilterWorkbench.fla

定义应用程序用户界面的主要文件。

flashapp/FilterWorkbench.as

为主应用程序用户界面提供功能的类;此类用作应用程序 FLA 文件的文档类。

在 flashapp/filterPanels 文件夹中:

BevelPanel.as

BlurPanel.as

ColorMatrixPanel.as

ConvolutionPanel.as

DropShadowPanel.as

GlowPanel.as

GradientBevelPanel.as

GradientGlowPanel.as

类集,为各面板(用于为单个滤镜设置选项)提供功能。

对于每个类而言,在主应用程序 FLA 文件库中,还有一个关联的 MovieClip 元件,其名称与类的名称相匹配(例如,“BlurPanel”元件链接到 BlurPanel.as 中定义的类)。构成用户界面的组件在这些元件中进行定位和命名。

flashapp/ImageContainer.as

作为屏幕上已加载图像的容器的显示对象

flashapp/BGColorCellRenderer.as

用于更改 DataGrid 组件中单元格的背景颜色的自定义单元格渲染器

flashapp/ButtonCellRenderer.as

用于将 Button 组件包含在 DataGrid 组件的单元格中的自定义单元格渲染器

套用滤镜的图像内容

com/example/programmingas3/filterWorkbench/ImageType.as

此类用作值对象,它包含应用程序可加载并对其应用滤镜的单个图像文件的类型和 URL。此类还包含一组代表实际可用图像文件的常量。

images/sampleAnimation.swf

images/sampleImage1.jpg

images/sampleImage2.jpg

应用程序中应用滤镜的图像和其他可视内容。

试验 ActionScript 滤镜

Filter Workbench 应用程序旨在帮助您试验各种滤镜效果,并为该效果生成相关的 ActionScript 代码。使用该应用程序,您可以从包含可视内容(包括位图图像和 Flash 创建的动画)的三种不同文件中进行选择,并可采用单独或与其他滤镜相结合的方式,将八种不同的 ActionScript 滤镜应用于选定的图像。此应用程序包含以下滤镜:

  • 斜角 (flash.filters.BevelFilter)

  • 模糊 (flash.filters.BlurFilter)

  • 颜色矩阵 (flash.filters.ColorMatrixFilter)

  • 卷积 (flash.filters.ConvolutionFilter)

  • 投影 (flash.filters.DropShadowFilter)

  • 发光 (flash.filters.GlowFilter)

  • 渐变斜角 (flash.filters.GradientBevelFilter)

  • 渐变发光 (flash.filters.GradientGlowFilter)

用户选定图像并将滤镜应用于图像后,应用程序将显示一个带有用于设置选定滤镜特定属性的控件的面板。例如,下列图像显示的是已选择“斜角”滤镜的应用程序:

如果用户调整滤镜属性,则预览将实时更新。用户还可以应用多个滤镜,方法是:自定义一个滤镜,单击“应用”按钮;自定义另一个滤镜,单击“应用”按钮,以此类推。

应用程序的滤镜面板具有一些功能和限制:

  • 颜色矩阵滤镜包含一组用于直接操作常用图像属性(包括亮度、对比度、饱和度和色相)的控件。另外,可以指定自定义颜色矩阵值。

  • 卷积滤镜只有在使用 ActionScript 时才可用,此滤镜包含一组常用的卷积矩阵值,也可指定自定义值。但是,虽然 ConvolutionFilter 类可以接受任意大小的矩阵,但 Filter Workbench 应用程序使用的是固定的 3 x 3 矩阵,这是最常用的滤镜大小。

  • 置换图滤镜和着色器滤镜仅在 ActionScript 中可用,在 Filter Workbench 应用程序中不可用。

创建滤镜实例

Filter Workbench 应用程序包含一个类集,各可用滤镜均有一个对应的类,各面板用这些类来创建滤镜。用户选定滤镜后,与滤镜面板相关联的 ActionScript 代码就将创建相应滤镜工厂类的实例。(这些类称为 工厂类 ,因为其用途在于创建其他对象的实例,这与实际工厂创建各产品极为相似)

只要用户更改面板上的属性值,面板的代码就会调用工厂类中的相应方法。各工厂类包含面板用于创建相应滤镜实例的特定方法。例如,如果用户选择“模糊”滤镜,则应用程序将创建 BlurFactory 实例。BlurFactory 类包含一个 modifyFilter() 方法,该方法接受三个参数: blurX blurY quality ,这三个参数一起用于创建所需的 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)); 
}

另一方面,如果用户选择“卷积”滤镜,因为该滤镜允许更大的灵活性,所以需要控制的属性就会更多。在 ConvolutionFactory 类中,如果用户在滤镜面板上选择不同的值,则将调用以下代码:

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)); 
}

请注意,在各例中,如果滤镜值发生变化,则工厂对象将调度 Event.CHANGE 事件,从而向侦听器‏通知滤镜的值已经改变。将滤镜实际应用于过滤内容的 FilterWorkbenchController 类将侦听该事件,以确定何时需检索滤镜的新副本并将其重新应用于过滤的内容。

FilterWorkbenchController 类无需知道各滤镜工厂类的特定详细信息,它只需知道滤镜已更改,并能够访问滤镜副本即可。为支持此目的,应用程序包含了一个 IFilterFactory 接口,该接口定义滤镜工厂类需提供的行为,以便应用程序的 FilterWorkbenchController 实例能够完成自己的工作。IFilterFactory 定义在 FilterWorkbenchController 类中使用的 getFilter () 方法:

function getFilter():BitmapFilter;

请注意, getFilter() 接口方法定义指定该方法返回一个 BitmapFilter 实例,而非特定类型的滤镜。BitmapFilter 类不定义特定类型的滤镜,而是用来构建所有滤镜类的基类。各滤镜工厂类定义 getFilter() 方法的特定实现,此时将返回对所创建滤镜对象的引用。例如,以下就是 ConvolutionFactory 类源代码的缩写版本:

public class ConvolutionFactory extends EventDispatcher implements IFilterFactory 
{ 
    // ------- Private vars ------- 
    private var _filter:ConvolutionFilter; 
    ... 
    // ------- IFilterFactory implementation ------- 
    public function getFilter():BitmapFilter 
    { 
        return _filter; 
    } 
    ... 
}

ConvolutionFactory 类在实现 getFilter() 方法时将返回一个 ConvolutionFilter 实例,尽管调用 getFilter() 的任何对象无需知道此返回结果。根据 ConvolutionFactory 所遵循的 getFilter() 方法的定义,此方法必须返回任意 BitmapFilter 实例,这些实例可能是任意 ActionScript 滤镜类的实例。

将滤镜应用于显示对象

如前所述,Filter Workbench 应用程序使用 FilterWorkbenchController 类的实例(下文称为“控制器实例”),该实例执行将滤镜应用于所选可视对象的实际任务。控制器实例必须首先知道滤镜需应用于哪些图像或可视内容,然后才能应用滤镜。用户选定图像后,应用程序将调用 FilterWorkbenchController 类中的 setFilterTarget() 方法,传入在 ImageType 类中定义的一个常量:

public function setFilterTarget(targetType:ImageType):void 
{ 
    ... 
    _loader = new Loader(); 
    ... 
    _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, targetLoadComplete); 
    ... 
}

控制器实例使用该信息来加载指定的文件,并将所加载的文件存储在一个名为 _currentTarget 的实例变量中:

private var _currentTarget:DisplayObject; 
 
private function targetLoadComplete(event:Event):void 
{ 
    ... 
    _currentTarget = _loader.content; 
    ... 
}

用户选择滤镜后,应用程序将调用控制器实例的 setFilter() 方法,为控制器提供对相关滤镜工厂对象的引用,此引用存储在名为 _filterFactory 的实例变量中。

private var _filterFactory:IFilterFactory; 
 
public function setFilter(factory:IFilterFactory):void 
{ 
    ... 
     
    _filterFactory = factory; 
    _filterFactory.addEventListener(Event.CHANGE, filterChange); 
}

请注意,正如上文所说明的那样,控制器实例并不知道为其提供的滤镜工厂实例的具体数据类型,它只知道对象实现 IFilterFactory 实例,这意味着它具有 getFilter() 方法,并可在滤镜更改时调度 change ( Event.CHANGE ) 事件。

如果用户改变滤镜面板中的滤镜属性,则控制器实例将通过滤镜工厂的 change 事件发现滤镜已发生更改,该事件调用控制器实例的 filterChange() 方法。而该方法又将调用 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(); 
}

将滤镜应用于显示对象的工作在 applyTemporaryFilter() 方法中进行。首先,控制器将通过调用滤镜工厂的 getFilter() 方法来检索对滤镜对象的引用。

var currentFilter:BitmapFilter = _filterFactory.getFilter();

控制器实例有一个名为 _currentFilters 的数组实例变量,所有曾应用于显示对象的滤镜均存储在该变量中。下一步就是将新近更新的滤镜添加到该数组:

_currentFilters.push(currentFilter);

然后,代码将滤镜数组分配给显示对象的 filters 属性,这会将滤镜实际应用于图像:

_currentTarget.filters = _currentFilters;

最后,由于此最近添加的滤镜仍旧是“工作”滤镜,不应将其永久应用于显示对象,因此将其从 _currentFilters 数组中删除:

_currentFilters.pop();

将此滤镜从数组中删除并不会影响已过滤的显示对象,因为在将滤镜数组分配给 filters 属性时,显示对象将生成滤镜数组的副本,而且显示对象使用的是内部数组而非原始数组。因此,对滤镜数组所做的任何更改均不会影响显示对象,直至数组被再次分配给显示对象的 filters 属性。