Пример фильтрации экранных объектов: Filter Workbench

Flash Player 9 и более поздних версий, Adobe AIR 1.0 и более поздних версий

Filter Workbench имеет пользовательский интерфейс, позволяющий применять к изображениям и другому визуальному содержимому различные фильтры и просматривать полученный в итоге код, который можно использовать для получения того же эффекта в ActionScript. Помимо предоставления инструмента для экспериментов с фильтрами это приложение располагает следующими техниками.

  • Создание экземпляров различных фильтров

  • Применение нескольких фильтров к экранному объекту

Получить файлы приложения для этого примера можно на странице www.adobe.com/go/learn_programmingAS3samples_flash_ru. Файлы приложения Filter Workbench находятся в папке Samples/FilterWorkbench. Приложение состоит из следующих файлов.

File

Описание

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

Пользовательский интерфейс (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

Набор классов, обеспечивающих функциональные возможности для каждой панели, используемой при выборе параметров для единичного фильтра.

Для каждого класса существует также связанный символ MovieClip в библиотеке FLA-файла основного приложения, чье имя совпадает с именем класса (например, символ «BlurPanel» связан с классом, определенном в файле BlurPanel.as). В этих символах содержатся данные об именах и расположении компонентов, входящих в состав пользовательского интерфейса.

flashapp/ImageContainer.as

Экранный объект, выступающий в роли контейнера для загруженного изображения на экране

flashapp/BGColorCellRenderer.as

Заказное средство визуализации ячеек, используемое для изменения цвета фона ячейки в компоненте DataGrid

flashapp/ButtonCellRenderer.as

Заказное средство визуализации ячеек, используемое для включения компонента кнопки в ячейку компонента 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 определяет метод getFilter(), используемый в классе FilterWorkbenchController:

function getFilter():BitmapFilter;

Учтите, что в определении метода интерфейса getFilter() указано, что он возвращает экземпляр BitmapFilter вместо конкретного типа фильтра. Класс 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; 
    } 
    ... 
}

В реализации метода getFilter() для класса ConvolutionFactory он возвращает экземпляр ConvolutionFilter, хотя любой объект, вызывающий метод getFilter(), не обязательно располагает информацией об этом. Согласно определению метода getFilter(), которому следует ConvolutionFactory, он должен вернуть любой экземпляр BitmapFilter, который может относиться к любому из классов фильтра ActionScript.

Применение фильтров к экранным объектам

Как пояснялось ранее, приложение Filter Workbench использует экземпляр класса FilterWorkbenchController (далее он будет называться «экземпляром контроллера»), который выполняет задачу применения фильтров к выделенному визуальному объекту. Перед тем, как экземпляр контроллера получит возможность применения фильтра, ему необходимо определить, к какому изображению или визуальному содержимому его следует применить. Когда пользователь выбирает изображение, приложение вызывает метод setFilterTarget() в классе FilterWorkbenchController, передавая одну из констант, определенных в классе 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();

Экземпляр контроллера имеет переменную экземпляра Array с именем _currentFilters, в которой он сохраняет все фильтры, примененные к экранному объекту. Следующее действие состоит в добавлении недавно обновленного фильтра к этому массиву:

_currentFilters.push(currentFilter);

Затем код присваивает массив фильтров свойству filters экранного объекта, которое выполняет фактическое применение фильтров к изображению:

_currentTarget.filters = _currentFilters;

Наконец, поскольку последний из добавленных фильтров является «рабочим», он не должен постоянно применяться к экранному объекту. Поэтому он удаляется из массива _currentFilters:

_currentFilters.pop();

Удаление этого фильтра из массива не влияет на фильтрованный экранный объект, поскольку экранный объект создает копию этого массива фильтров, когда он присваивается свойству filters и использует этот внутренний массив вместо оригинального. По этой причине любые изменения, внесенные в массив фильтров, не влияют на экранный объект до тех пор, пока массив не будет снова присвоен свойству filters экранного объекта.