О выходе Flash Player 10 beta aka «Astro» не писал только ленивый и «Garbage Collector». Однако последний, из этих двух, все же решил исправиться.
Одной из «фишек» нового плеера стала возможность создавать свои собственные графические фильтры. Вот, собственно, об этом сегодня и пойдет речь.
Создание собственных фильтров стало возможно благодаря новому продукту от Adobe под названием Pixel Bender Toolkit (раннее известного как Adobe Image Foundation Toolkit). Pixel Bender Toolkit использует собственный C-подобный язык описания алгоритмов преобразования изображений. Что ж, давайте попробуем создать собственный фильтр и применить его в нашем ActionScript 3 приложении.
Шаг 1: Подготовка
Прежде чем приступить к нашему знакомству с обозначенной темой, нам придется немного подготовиться. Во-первых, нам потребуется сам Pixel Bender Toolkit для написания фильтра и его компиляции. А во-вторых, нам потребуется настроить свою среду разработки. Приступим.
Инструкцию по скачиванию и установке Pixel Bender Toolkit можно найти на Adobe Labs. О том, как настроить свою среду разработки, можно почитать следующие статьи:
- для для Flex Builder и mxmlc: «Targeting Flash Player 10 Beta with Flex SDK 3.0.x»;
- для FlashDevelop: «Налаживаем компиляцию под Flash Player 10 из FlashDevelop IDE»;
- для FDT: «FDT + Astro = Love!».
Шаг 2: Написание и компиляция собственного эффекта
Для первого знакомства, я думаю, стоит взять простой эффект — сепия. Так как пока мои навыки написания собственных фильтров на Pixel Bender не велики, я решил воспользоваться готовым решением (правда код подвергся небольшой корректировке в свете некоторых изменений в языке).
<languageversion : 1.0;>
kernel Sepia
< namespace: "popforge::ImageProcessing";
vendor: "Joa Ebert";
version: 1;
description: "A good looking sepia filter using Y transform";
>
{
input image3 source;
output pixel3 result;
void evaluatePixel()
{
pixel3 color = sampleLinear(source, outCoord());
float y = 0.299 * color.r + 0.587 * color.g + 0.114 * color.b;
float r = min(1.0, y + 0.19);
float g = max(0.0, y - 0.055);
float b = max(0.0, y - 0.22);
result = pixel3(r, g, b);
}
}
И так у нас есть исходный код фильтра. Скомпилируем его.
Запускаем Pixel Bender Toolkit и создаем новый фильтр (File → New Pixel Bender Kernel Filter). Теперь в окно редактора вставляем исходный код и компилируем его (File → Export Pixel Bender Byte Code for Flash). Полученный файл с расширение .pbj мы и будем использовать в нашем приложении.
Шаг 3: Написание приложения
Для демонстрации применения фильтра мы напишем простое приложение. В его задачи будет входить загрузка изображения, его отображение, загрузка фильтра и показ этого же изображения, но уже с применением фильтра. Дальше подробно расписывать не буду, ибо вся суть в коде. Остановлюсь лишь на некоторых моментах. Для применения фильтра нам потребуется новоиспеченный класс flash.display.Shader, который должен получить фильтр в бинарном виде. Результат применения фильтра мы отрисовываем в экземпляре Shape с помощью метода graphics.beginShaderFill.
-
package
-
{
-
import flash.display.Bitmap;
-
import flash.display.Loader;
-
import flash.display.Shader;
-
import flash.display.Shape;
-
import flash.display.Sprite;
-
import flash.display.StageScaleMode;
-
import flash.events.Event;
-
import flash.net.URLLoader;
-
import flash.net.URLLoaderDataFormat;
-
import flash.net.URLRequest;
-
-
[SWF(width='500', height='510', frameRate='31', backgroundColor='0x000000')]
-
public class RuntimePixelBenderExample extends Sprite
-
{
-
private var _image:Bitmap = null;
-
private var _shape:Shape = null;
-
private var _imageLoader:Loader = null;
-
private var _filterLoader:URLLoader = null;
-
private var _sepiaShader:Shader = null;
-
-
public function RuntimePixelBenderExample()
-
{
-
stage.scaleMode = StageScaleMode.NO_SCALE;
-
loadImage();
-
}
-
-
private function loadImage ():void
-
{
-
_imageLoader = new Loader();
-
_imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
-
_imageLoader.load(new URLRequest("assets/image/bender.jpg"));
-
}
-
-
private function loadFilter ():void
-
{
-
_filterLoader = new URLLoader();
-
_filterLoader.dataFormat = URLLoaderDataFormat.BINARY;
-
_filterLoader.addEventListener(Event.COMPLETE, onFilterLoaded);
-
_filterLoader.load(new URLRequest("assets/filter/Sepia.pbj"));
-
}
-
-
private function applyFilter ():void
-
{
-
_sepiaShader.data.source.input = _image.bitmapData;
-
-
_shape = new Shape();
-
_shape.y = 255;
-
-
_shape.graphics.beginShaderFill(_sepiaShader);
-
_shape.graphics.drawRect(0, 0, 500, 255);
-
_shape.graphics.endFill();
-
-
addChild(_shape);
-
}
-
-
private function onImageLoaded (event:Event):void
-
{
-
_image = _imageLoader.content as Bitmap;
-
addChild(_image);
-
loadFilter();
-
}
-
-
private function onFilterLoaded (event:Event):void
-
{
-
_sepiaShader = new Shader(_filterLoader.data);
-
applyFilter();
-
}
-
}
-
}
Необходимость в загрузке фильтра во время исполнения иногда может вызвать некоторые трудности. Но мы можем это легко обойти, включив байткод фильтра в приложение на этапе компиляции (как это делается, можно узнать из статьи «Включение файлов в SWF в виде байтовой последовательности»). В этом случае наше приложении будет выглядеть так:
-
package
-
{
-
import flash.display.Bitmap;
-
import flash.display.Loader;
-
import flash.display.Shader;
-
import flash.display.Shape;
-
import flash.display.Sprite;
-
import flash.display.StageScaleMode;
-
import flash.events.Event;
-
import flash.net.URLRequest;
-
import flash.utils.ByteArray;
-
-
[SWF(width='500', height='510', frameRate='31', backgroundColor='0x000000')]
-
public class CompiledPixelBenderExample extends Sprite
-
{
-
private var _image:Bitmap = null;
-
private var _shape:Shape = null;
-
private var _imageLoader:Loader = null;
-
-
[Embed(source="assets/filter/Sepia.pbj", mimeType="application/octet-stream")]
-
private var SepiaFilter:Class;
-
-
private var _sepiaShader:Shader = null;
-
-
public function CompiledPixelBenderExample ()
-
{
-
stage.scaleMode = StageScaleMode.NO_SCALE;
-
loadImage();
-
}
-
-
private function loadImage ():void
-
{
-
_imageLoader = new Loader();
-
_imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
-
_imageLoader.load(new URLRequest("assets/image/bender.jpg"));
-
}
-
-
private function applyFilter ():void
-
{
-
_sepiaShader = new Shader(new SepiaFilter());
-
_sepiaShader.data.source.input = _image.bitmapData;
-
-
_shape = new Shape();
-
_shape.y = 255;
-
-
_shape.graphics.beginShaderFill(_sepiaShader);
-
_shape.graphics.drawRect(0, 0, 500, 255);
-
_shape.graphics.endFill();
-
-
addChild(_shape);
-
}
-
-
private function onImageLoaded (event:Event):void
-
{
-
_image = _imageLoader.content as Bitmap;
-
addChild(_image);
-
applyFilter();
-
}
-
}
-
}
Исходный код проекта можно скачать здесь.
Послесловие
Новые возможности Flash Player 10 вскоре сильно изменят внешний вид будущих flash-приложений. И с одной из таких возможностей мы уже познакомились. Замечу, мы рассмотрели пример применения простого фильтра, не требующего параметризации. В остальных случаях читайте документацию (она идет в комплекте с Pixel Bender Toolkit), пишите фильтры и делайте мир лучше (жду русскоязычный блог про Pixel Bender). Что ж, на этом на сегодня все. Надеюсь вам было интересно.
Для тех, кто все еще здесь
Напоследок, несколько полезных ссылок:
- Статья от Senocular'а, посвященная новому API для рисования;
- форум Adobe, посвященный Flash Player 10;
- галерея фильтров Pixel Bender (часть фильтров написана еще под Hydra и поэтому требует корректировки);
- Раздел блога Joa Ebert, посвященный Hydra (Pixel Bender).




[...] новых методов рисования в 10 плеере, примеры и демки. . Использование фильтров Pixel Bender в ActionScript 3 by Garbage [...]