Март 2011
Руководство по actionscript. часть 5, стр. 055
Метод copyPixels ( ) предпочтительно применять для перемещения пикселов между двумя объектами BitmapData. Перемещение пикселов между растровыми изображениями является распространенной операцией в приложениях для работы с графикой и в видеоиграх. Рассмотрим несколько примеров.
Попрактикуемся в использовании базового синтаксиса метода copyPixels ( ), создав квадраты синего и красного цвета и скопировав область квадрата синего цвета в квадрат красного цвета.
// Создаем квадраты (размером 20 х 20 пикселов каждый)
var redSquare-.BitmapData = new BitmapData(20. 20. true. OxFFFFOOOO);
var blueSquare:BitmapData = new BitmapData(20. 20. true. OxFFOOOOFF):
// Определяем прямоугольную область, которая будет скопирована из объекта
// blueSquare в объект redSquare
var sourceRect:Rectangle = new Rectangle(5. 5. 10. 5):
// Определяем точку в объекте redSquare. в которую будет помещена // прямоугольная область из объекта blueSquare var destPoint:Point = new Point(0.0);
// Копируем пикселы
redSquare. copyPixels(blueSquare, sourceRect, destPoint);
// Связываем объект BitmapData redSquare с объектом Bitmap для отображения // на экране
var b:Bitmap = new Bitmap(redSquare): addChild(b):
В листинге 26.11 представлен другой пример — создание фотографии с краями неправильной формы, как было описано ранее при рассмотрении параметра обь — eKTBitmapDataKaHdnaAlphd. Понять код вам помогут комментарии. Обратите особое внимание на метод makeScrapbooklmage ( ).
Руководство по actionscript. часть 5, стр. 056
Листинг 26.11. Эффект старой фотографии
package { import flash. display.*; import flash. events.*; import flash. geom.*; import flash. net.*;
public class ScrapbookImage extends Sprite { private var numl_oaded:int = 0;
private var photoLoader:Loader; // Загрузчик фотографии private var borderLoader:Loader; // Загрузчик рамки
// Конструктор
public function ScrapbookImage ( ) { // Загружаем фотографию photoLoader = new Loader( );
photoLoader. contentLoaderInfo. addEventLi stener(Event. INIT,
initListener);
photoLoader.1oad(new URLRequest(«photo. jpg»));
// Загружаем рамку borderLoader = new Loader( );
borderLoader. contentLoaderInfo. addEventListener(Event. INIT,
initListener);
borderLoader.1oad(new URLRequest(«border. png»));
}
// Обрабатывает события Event. INIT для загруженных изображений private function initListener (e:Event):void {
numLoaded++;
if (numLoaded == 2) { makeScrapbookImage( );
}
}
// Объединяет изображение рамки с изображением фотографии, чтобы создать
// эффект старой фотографии
public function makeScrapbooklmage ( ):void {
// Получаем объект BitmapData для фотографии
var photoData:BitmapData = Bitmap(photol_oader. content) .bitmapData;
// Получаем объект BitmapData для рамки
var borderData:BitmapData = Bitmap(borderl_oader. content).bitmapData; // Создаем объект BitmapData, который будет хранить завершенное // изображение фотографии
var scrapbooklmage:BitmapData = new BitmapData(borderData. width,
borderData. height, true,
OxFFFFFFFF);
// Копируем пикселы из фотографии.
Руководство по actionscript. часть 5, стр. 057
// применяя значения канала Alpha рамки
scrapbookImage. copyPi xels(photoData.
borderData. rect, new Point(O. O), borderData, new Point(O. O). true);
// Связываем объект BitmapData scrapbooklmage с объектом Bitmap
// для отображения на экране
var b:Bitmap = new Bitmap(scrapbooklmage):
addChild(b);
b. x = 100:
b. y = 75;
}
}
}
На рис. 26.8 проиллюстрированы результаты выполнения кода из листинга 26.11. Исходное изображение показано слева, а изображение с «краями» — справа.
Руководство по actionscript. часть 5, стр. 058
Рис. 26.8. Эффект старой фотографии
Изображения и код из листинга 26.11 доступны в Интернете по адресу http://www. moock. org/eas3/examples.
Метод copyPixels ( ) также предоставляет эффективный способ для повторно-то использования набора значений пикселов. Например, в двухмерных видеоиграх фоновые изображения зачастую генерируются динамически из небольшой группы готовых растровых изображений, называемых мозаиками. По мере перемещения игрока по виртуальному миру программа отображает соответствующий набор
фоновых мозаик. С помощью метода copyPixel s ( ) каждая мозаика копируется из повторно используемого объекта BitmapData в фоновое изображение, отображаемое на экране. Хотя подробное рассмотрение системы мозаичных фоновых изображений выходит за рамки данной книги, полнофункциональный пример мозаики на языке ActionScript может быть загружен с сайта http://www. moock. org/ eas3/examples.
Применение фильтров и эффектов
Для создания графических эффектов мы можем использовать следующий широкий диапазон инструментов, предоставляемых классом BitmapData.
? ColorTransf orm ( ) — из меняет цвета с помощью объекта Colo rT г ans form, который предоставляет базовый интерфейс для простейших цветовых преобразований (для более сложного управления цветовыми преобразованиями используйте класс ColorMatrixFilter).
? applyFiIter ( ) — изменяет растровое изображение с помощью предопределенных фильтров-эффектов, например падающей тени или размытия. Дополнительную информацию можно найти далее в разделе.
? noise ( ) — заполняет растровое изображение случайными значениями цветов из настраиваемых диапазонов. На рис. 26.9 показано изображение, созданное с помощью метода п о i s е ( ).
Рис. 26.9. Растровое изображение, заполненное шумом
? perlinNoise( ) — заполняет растровое изображение случайными образцами значений цветов, выполненных в органическом стиле. На рис. 26.10 показано изображение, сгенерированное с помощью метода perlinNoise ( ). Результаты выполнения метода perlinNoise ( ) обычно не используются напрямую; этот фильтр часто применяется вместе с другими фильтрами для создания имитации волн, пламени, облаков, воды, текстуры древесины и ландшафтов. Общее описание шума Перлина можно найти во вводной лекции Кена Пер-лина (Ken Perlin) по адресу http://www. noisemachine. com/talkl. Пример на языке ActionScript, демонстрирующий использование метода perlinNoise ( ) для создания текстуры древесины, можно найти по адресу http://www. connectedpixel. com/blog/texture/wood. Пример создания текстуры мрамора вы найдете по адресу http://www. connectedpixel. com/blog/texture/marble.
Руководство по actionscript. часть 5, стр. 059
Рис. 26.10. Растровое изображение, заполненное с помощью шума Перлина
? paletteMap ( ) —заменяет цвета в изображении цветами из таблицы перекодировки или другого изображения.
? pixelDissolve ( ) — при циклическом использовании в анимации создает эффект перехода между двумя изображениями или пиксел за пикселом заменяет цвета изображения указанным цветом (пример замены цветов изображения указанным цветом можно найти в листинге 26.9).
? threshold ( ) — преобразует пикселы из некоторого диапазона цветов к новому указанному значению цвета.
Хотя каждый из перечисленных методов предоставляет множество возможностей для работы с графикой, в этом разделе мы сосредоточим внимание на инструменте, который, возможно, обладает наиболее универсальной применимостью, — методе applyFilter ( ). Дополнительную информацию о других методах, предназначенных для создания эффектов, можно найти в описании класса BitmapData в справочнике по языку ActionScript корпорации Adobe.
Применение фильтров. Чтобы предоставить программистам удобный способ применения распространенных графических эффектов к растровому изображению, язык ActionScript предлагает набор готовых графических фильтров.
Фильтры, рассматриваемые в этом разделе, могут на постоянной основе применяться к объекту BitmapData на уровне пикселов, но они также могут применяться к любому отображаемому объекту или удаляться из него динамически. Дополнительную информацию можно получить в описании переменной экземпляра filters класса DisplayObject в справочнике по языку ActionScript корпорации Adobe.
Каждый предопределенный фильтр представляется собственным классом в пакете flash. fil ter s. Например, фильтр размытия, который делает растровое изображение размытым, представляется классом flash. filters. BlurFilter.
Некоторые фильтры могут быть легко использованы даже теми разработчиками, которые не имеют никакого опыта в программировании графики. К этой категории относятся следующие фильтры: фаска, размытие, падающая тень и свечение, которые представляются классами BevelFil ter (и его разновидностью с градиентом GradientBevelFilter), BlurFilter, DropShadowFilter и GlowFilter (и его разновидностью с градиентом GradientGlowFilter).
Другие фильтры требуют понимания фундаментальных методик программирования графики, например таких, как искривление, замещение и цветовые матрицы. К этой категории относятся следующие фильтры: матричное искривление, карта замещения и преобразования цветовых матриц, которые представляются классами
ConvolutionFilter, DisplacementMapFilterи ColorMatrixFilter.
Руководство по actionscript. часть 5, стр. 060
Независимо от типа фильтра, методика применения фильтра к растровому изображению в языке ActionScript остается одной и той же.
1. Создать экземпляр класса нужного фильтра.
2. Передать созданный экземпляр класса фильтра в метод applyFilter( ).
Например, чтобы применить фильтр размытия к растровому изображению, мы создаем экземпляр класса BlurFilter, используя следующий обобщенный формат:
new BlurFilter(размытие/. размытиеУ, качество)
Здесь размытиеХ и размытиеУ обозначают дистанцию размытия каждого пиксела по горизонтали и вертикали, а качество — качество визуализации данного эффекта, выражаемое через одну из трех констант класса BitmapFilterQuality.
Следующий код создает эффект размытия среднего качества, охватывающий 15 пикселов по вертикали и горизонтали:
var blurFiIter:BlurFilter =
new BlurFilter(15. 15, BitmapFiIterQuality. MEDIUM);
После создания фильтра мы применяем его к объекту BitmapData, используя следующий код:
целевойОбъектШtmapData. applyFi 1 ter(исходный0бьектВ1tmapData, исходнаяОбласть. целеваяТочка, фильтр):
Здесь целевойОбьектВ!’tmapData — это объект BitmapData, в который будут перенесены пикселы с примененным фильтром. Рассмотрим параметры метода applyFilter( ).
Руководство по actionscript. часть 5, стр. 061
? исходныйОбъектВ!’tmapData — объект BitmapData, к которому будет применен фильтр. Объекты исходный0бьектВ1 tmapData и целевой0бъектВ1 tmapData могут быть одним объектом, позволяя применять фильтр непосредственно к некоторому объекту BitmapData.
? исходнаяОбласть — объект Rectangle, определяющий область объекта исход-ныйОбъектВ! tmapData, к которой будет применен фильтр. Чтобы применить фильтр ко всему растровому изображению, используйте переменную исход-ный0бъектВ1tmapData. rect.
? целеваяТочка — объект Point, определяющий позицию внутри объекта целевой-ОбьектВ! tmapData, куда будут помещаться пикселы с примененным фильтром. Обратите внимание, что параметр целеваяТочка соответствует левому верхнему углу указанного объекта исходнаяОбласть, а не левому верхнему углу области пикселов, к которой применяется операция фильтрации. Дополнительная информация приводится далее, при рассмотрении метода generateFilterRect ( ).
? фильтр — это объект используемого фильтра, например экземпляр какого-либо из следующих классов: BevelFilter, GradientBevelFilter,
BlurFilter, DropShadowFilter, GlowFilter, GradientGlowFilter, ConvolutionFilter, DisplacementMapFilter или ColorMatrixFilter.
Следующий код применяет созданный ранее объект BlurFilter ко всему объекту BitmapData:
bitmapData. applyFi1terCbitmapData. bitmapData. rect. new Point(O. O). blurFilter);
На рис. 26.11 показаны результаты применения к изображению объекта BlurFilter размером 15×15 пикселов. .
Рис. 26.11. Примененный фильтр размытия
Когда фильтр применяется к растровому изображению, размеры результирующего растрового изображения зачастую оказываются больше размеров исходного. Например, результатом применения фильтра падающей тени может оказаться тень, выходящая за границы исходного растрового изображения. Чтобы полностью сохранить результаты применения фильтра, мы должны убедиться, что целевое изображение способно уместить все переносимые пикселы с примененным фильтром. Чтобы определить размеры растрового изображения, достаточные для сохранения результатов применения фильтра, мы используем метод экземпляра generateFilterRect ( ) класса BitmapData. Этот метод возвращает объект Rectangle, который обозначает область пикселов, затрагиваемую данной операцией фильтрации. Метод имеет следующий обобщенный вид:
исходныйОбъектЕН tmapData. generateFi1terRect(исходнаяОбласть, фильтр)
Метод generateFilterRect ( ) возвращает объект Rectangle, который обозначает область пикселов, затрагиваемую указанным объектом фильтра (филь тр) в том случае, если этот фильтр будет применен к указанной прямоугольной области (исходнаяОбласть) указанного объекта BitmapData (исходный0бъектВ1 tmapData).
Руководство по actionscript. часть 5, стр. 062
^ I Метод generateFilterRect^ ) на самом деле не применяет фильтр. Он просто определяет об-м$ j ц ласть пикселов, которая будет затронута данным фильтром в случае его применения. * д А
Попробуем применить метод generateFilterRect ( ) на практике. Наша цель— создать растровое изображение с эффектом падающей тени. Сначала мы создаем исходное растровое изображение без эффекта падающей тени. Исходное изображение представляет собой квадрат серого цвета размером 20 х 20 пикселов.
var origBitmap:BitmapData = new BitmapData(20. 20. false. OxFFDDDDDD);
Далее мы создаем объект DropShadowFil ter. Конструктор его класса имеет следующий вид:
DropShadowFi 1 ^(расстояние: Number=4.0, угол: Number=45, цвет: ui nt=0, прозрачность :Number=l. О, размытиеХ:Number=4.О. размытиеУ:Number=4.О. интенсивность :Number=l. О, качество:int=l, внутренняя:Boolean=false. выколотка:Boolean = false, скрытьОбъект:Boolean = false)
Сведения о различных параметрах конструктора класса DropShadowFil ter можно найти в описании этого класса в справочнике по языку ActionScript корпорации Adobe. Вот наш объект DropShadowFilter:
var dsFiIter:DropShadowFiIter = new DropShadowFilter(4, 45, 0,
1. 10. 10.
2, BitmapFilterQuality. MEDIUM):
Далее используем метод generateFilterRect ( ), чтобы определить, насколько увеличатся размеры нашего исходного изображения после применения объекта
DropShadowFilter:
var filterRect:Rectangle = origBitmap. generateFilterRect(origBitmap. rect,
dsFilter);
Теперь мы можем создать новое растровое изображение с необходимыми размерами, в которое будет перенесено исходное растровое изображение с примененным фильтром падающей тени. Обратите внимание, что мы указываем высоту и ширину нового растрового изображения с использованием результатов, возвращаемых методом generateFilterRect ( ) (выделены полужирным шрифтом):
var fi nalBi tmap:Bi tmapData = new BitmapData(filterRect. width,
fi1terRect. hei ght. true);
Целевой объект BitmapData для фильтра эффекта падающей тени должен быть прозрачным.
Руководство по actionscript. часть 5, стр. 063
Теперь, когдау нас есть исходное растровое изображение, объект DropShadowFilter и целевое растровое изображение с подходящими размерами, мы можем применить наш фильтр падающей тени, как показано в следующем коде:
fi nalBi tmap. applyFi1ter(ori gBi tmap. ori gBi tmap. rect.
new PointC-filterRect. x, — filterRect. y). dsFilter);
В данном коде обратите внимание, что передаваемый параметр целеваяТочка смещает пикселы с примененным фильтром на значение, равное расстоянию, на которое результат применения фильтра выходит за верхнюю и левую границу указанного параметра исходнаяОбласть. В нашем примере эффект фильтра применяется ко всему растровому изображению, поэтому левый верхний угол объекта исходнаяОбласть находится в точке с координатой (0; 0). Размытие падающей тени расширяет исходное растровое изображение на 9 пикселов вверх и на 9 пикселов влево. Следовательно, координата по оси X сгенерированного фильтром прямоугольника, как и координата по оси Y, будет равна -9. Чтобы переместить левый верхний угол
области пикселов с примененным фильтром вниз и вправо (в левый верхний угол растрового изображения, содержащего результат применения фильтра), мы указываем объект целеваяТочка, который использует обратные значения координат по осям X и Y прямоугольника фильтра:
new PointC-filterRect. x, — filterRect. у)
Для обзора ниже представлен весь код, создающий эффект падающей тени:
var origBitmap:BitmapData = new BitmapData(20, 20, false. OxFFDDDDDD); var dsFilter:DropShadowFiIter = new DropShadowFilter(4, 45, 0,
1. 10. 10.
2. BitmapFilterQuality. MEDIUM); var filterRect:Rectangle = origBitmap. generateFilterRectCorigBitmap. rect,
dsFilter);
var final Bitmap:BitmapData = new BitmapData(filterRect. width.
Руководство по actionscript. часть 5, стр. 064
FilterRect. height. true); finalBitmap. applyFilter(origBitmap. origBitmap. rect.
new PointC-filterRect. x. — filterRect. y).
dsFilter);
На рис. 26.12 показаны результаты выполнения предыдущего кода.
J
Рис. 26.12. Изображение с примененным фильтром падающей тени
Теперь, когда мы рассмотрели основы использования фильтров, вернемся к листингу 26.11, чтобы улучшить эффект старой фотографии. В листинге 26.12 показан новый код. Общая методика создания и применения фильтров в этом примере уже должна быть вам знакома. Тем не менее в примере используется специальный фильтр, который мы еще не рассматривали: ColorMatrixFilter. Этот фильтр с помощью матричных преобразований изменяет цвета в растровом изображении для создания таких эффектов, как, например, настройка яркости, контраста и насыщенности, изменение оттенка. Этот пример демонстрирует, как использовать фильтр ColorMatrixFilter в его исходном виде, но по крайней мере два разработчика предоставляют бесплатный код для выполнения распространенных матричных преобразований:
? класс ColorMatrix Марио Клингеманна (Mario Klingemann) — http://www. quasimondo. com/archives/000565.php;
? класс ColorMatrix Гранта Скиннера (Grant Skinner) — http://www. gskinner. com/ blog/archives/2005/09/flash_8_source. html.
Общую информацию по цветовым матричным преобразованиям можно найти в статье « Using Matrices for Transformations, Color Adjustments, and Convolution Effects in Flash» Фила Чанга (Phil Chung), доступной по адресу http://www. adobe. com/devnet/ flash/articles/matrix_transformations_04.html.
Листинг 26.12. Эффект старой фотографии, теперь с фильтрами
package { import flash. display.*;
import flash. events.*;
import flash. geom.*;
import flash. net.*;
import flash. filters.*;
public class Scrapbooklmage extends Sprite { private var numl_oaded:int = 0;
private var photoLoader.-Loader; // Загрузчик фотографии
private var borderLoader-.Loader; // Загрузчик рамки
public function Scrapbooklmage ( ) { // Загружаем фотографию photoLoader = new Loader( );
photoLoader. contentLoaderInfo. addEventListener(Event. INIT.