поиск

Использование фильтров Pixel Bender в ActionScript 3

Намусорил: Алексей «Vooparker» Аникутин
В категории: ActionScript 3, Обзоры

О выходе 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. О том, как настроить свою среду разработки, можно почитать следующие статьи:

Шаг 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.

Actionscript:
  1. package
  2. {
  3.     import flash.display.Bitmap;
  4.     import flash.display.Loader;
  5.     import flash.display.Shader;
  6.     import flash.display.Shape;
  7.     import flash.display.Sprite;
  8.     import flash.display.StageScaleMode;
  9.     import flash.events.Event;
  10.     import flash.net.URLLoader;
  11.     import flash.net.URLLoaderDataFormat;
  12.     import flash.net.URLRequest;
  13.    
  14.     [SWF(width='500', height='510', frameRate='31', backgroundColor='0x000000')]
  15.     public class RuntimePixelBenderExample extends Sprite
  16.     {
  17.         private var _image:Bitmap = null;
  18.         private var _shape:Shape = null;
  19.         private var _imageLoader:Loader = null;
  20.         private var _filterLoader:URLLoader = null;
  21.         private var _sepiaShader:Shader = null;
  22.        
  23.         public function RuntimePixelBenderExample()
  24.         {
  25.             stage.scaleMode = StageScaleMode.NO_SCALE;
  26.             loadImage();
  27.         }
  28.        
  29.         private function loadImage ():void
  30.         {
  31.             _imageLoader = new Loader();
  32.             _imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
  33.             _imageLoader.load(new URLRequest("assets/image/bender.jpg"));
  34.         }
  35.        
  36.         private function loadFilter ():void
  37.         {
  38.             _filterLoader = new URLLoader();
  39.             _filterLoader.dataFormat = URLLoaderDataFormat.BINARY;
  40.             _filterLoader.addEventListener(Event.COMPLETE, onFilterLoaded);
  41.             _filterLoader.load(new URLRequest("assets/filter/Sepia.pbj"));
  42.         }
  43.        
  44.         private function applyFilter ():void
  45.         {
  46.             _sepiaShader.data.source.input = _image.bitmapData;
  47.            
  48.             _shape = new Shape();
  49.             _shape.y = 255;
  50.            
  51.             _shape.graphics.beginShaderFill(_sepiaShader);
  52.             _shape.graphics.drawRect(0, 0, 500, 255);
  53.             _shape.graphics.endFill();
  54.            
  55.             addChild(_shape);
  56.         }
  57.        
  58.         private function onImageLoaded (event:Event):void
  59.         {
  60.             _image = _imageLoader.content as Bitmap;
  61.             addChild(_image);
  62.             loadFilter();
  63.         }
  64.        
  65.         private function onFilterLoaded (event:Event):void
  66.         {
  67.             _sepiaShader = new Shader(_filterLoader.data);
  68.             applyFilter();
  69.         }
  70.     }
  71. }

Необходимость в загрузке фильтра во время исполнения иногда может вызвать некоторые трудности. Но мы можем это легко обойти, включив байткод фильтра в приложение на этапе компиляции (как это делается, можно узнать из статьи «Включение файлов в SWF в виде байтовой последовательности»). В этом случае наше приложении будет выглядеть так:

Actionscript:
  1. package
  2. {
  3.     import flash.display.Bitmap;
  4.     import flash.display.Loader;
  5.     import flash.display.Shader;
  6.     import flash.display.Shape;
  7.     import flash.display.Sprite;
  8.     import flash.display.StageScaleMode;
  9.     import flash.events.Event;
  10.     import flash.net.URLRequest;
  11.     import flash.utils.ByteArray;
  12.    
  13.     [SWF(width='500', height='510', frameRate='31', backgroundColor='0x000000')]
  14.     public class CompiledPixelBenderExample extends Sprite
  15.     {
  16.         private var _image:Bitmap = null;
  17.         private var _shape:Shape = null;
  18.         private var _imageLoader:Loader = null;
  19.        
  20.         [Embed(source="assets/filter/Sepia.pbj", mimeType="application/octet-stream")]
  21.         private var SepiaFilter:Class;
  22.        
  23.         private var _sepiaShader:Shader = null;
  24.        
  25.         public function CompiledPixelBenderExample ()
  26.         {
  27.             stage.scaleMode = StageScaleMode.NO_SCALE;
  28.             loadImage();
  29.         }
  30.        
  31.         private function loadImage ():void
  32.         {
  33.             _imageLoader = new Loader();
  34.             _imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
  35.             _imageLoader.load(new URLRequest("assets/image/bender.jpg"));
  36.         }
  37.        
  38.         private function applyFilter ():void
  39.         {
  40.             _sepiaShader = new Shader(new SepiaFilter());
  41.             _sepiaShader.data.source.input = _image.bitmapData;
  42.            
  43.             _shape = new Shape();
  44.             _shape.y = 255;
  45.            
  46.             _shape.graphics.beginShaderFill(_sepiaShader);
  47.             _shape.graphics.drawRect(0, 0, 500, 255);
  48.             _shape.graphics.endFill();
  49.            
  50.             addChild(_shape);
  51.         }
  52.        
  53.         private function onImageLoaded (event:Event):void
  54.         {
  55.              _image = _imageLoader.content as Bitmap;
  56.              addChild(_image);
  57.              applyFilter();
  58.         }
  59.     }
  60. }

Исходный код проекта можно скачать здесь.

Послесловие

Новые возможности Flash Player 10 вскоре сильно изменят внешний вид будущих flash-приложений. И с одной из таких возможностей мы уже познакомились. Замечу, мы рассмотрели пример применения простого фильтра, не требующего параметризации. В остальных случаях читайте документацию (она идет в комплекте с Pixel Bender Toolkit), пишите фильтры и делайте мир лучше (жду русскоязычный блог про Pixel Bender). Что ж, на этом на сегодня все. Надеюсь вам было интересно.

Для тех, кто все еще здесь

Напоследок, несколько полезных ссылок:



Kомментариев - 6 к «Использование фильтров Pixel Bender в ActionScript 3»

Flash, Flex, Air » Adobe Flash Player 10 Astro [21 мая, 2008 в 10:13]

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

__i [21 мая, 2008 в 14:23]

примеры фильтров есть тут

http://blog.je2050.de/category/hydra/

автор этого блог просто мегамонстр в работе с изображениями

Vooparker [21 мая, 2008 в 14:33]

2__i: Спасибо, дополнил список :)

pride_conan [23 мая, 2008 в 00:54]

сенкс за статью - наглядный пример.
а вот фильтры писать это не так просто((

Юрий Яровой [23 мая, 2008 в 02:42]

Ну мне кажется, что это не так просто только в самом начале. А дальше будет все легче и легче... ;-)

Vooparker [23 мая, 2008 в 23:05]

Саш, я не думаю, что писать фильтры сложная задача :) по крайней мере синтаксис вполне читаемый (а сам реф по языку всего 38 страниц). Другое дело придумать этот фильтр и уже затем понять как его реализовать, вот это как раз пока и в новинку нашему брату. Еще один момент который меня немного смущает реализация использования фильтров в actionscript, я могу в принципе согласиться с представление фильтра в виде ByteArray, но дальнейшее его применение через beginShaderFill пока выглядит весьма сомнительно. С другой стороны я думаю к релизу десятки мы получим совершенно иную реализацию. В этой связи может возникнуть резонный вопрос, а стоит ли сейчас разбираться с тем, что мы имеем в бете. Для себя я ответил на этот вопрос вцелом положительно. Ведь по-большому счете совершенно неважно как выглядит реализации, главное насколько производительный и впечатляющий результат мы можем получить и в этом контексте возможность потрогать десятку уже сейчас является весьма привлекательной.

Написать комментарий:

 

Bы можете использовать следующие теги для форматирования: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



User's collector

Внимание!
Эта опция станет доступной только после того как вы авторизуетесь.


 запомнить меня 
Я новый пользователь

На правах рекламы