Руководство по actionscript. часть 5, стр. 048

Рассмотрим пример каждого случая. Сначала мы создадим две векторные фигуры — прямоугольник и эллипс — и перенесем их в один объект BitmapData. Этот код показан в листинге 26.8.



ТА,

Векторные фигуры, переносимые в объект BitmapData, не обязаны находиться в списке отображения. Совершенно нормально создавать векторные объекты, не отображая их JJsV на экране, просто для того, чтобы скопировать эти объекты в растровое изображение (как показано в листингах 26.8 и 26.9).

Листинг 26.8. Отображаемые объекты, объединенные в растровом изображении

// Создаем прямоугольник var rect:Shape = new Shape( ); rect. graphics. begi nFi11(OxFFOOOO); rect. graphi cs. drawRect(0,0,25,50);

// Создаем эллипс var el 1ipse:Shape = new Shape( ); ell ipse. graphics. beginFi11(OxOOOOFF); el 1i pse. graphi cs. drawEl1i pse(0,0,35,25);

// Создаем объект BitmapData. Он будет выступать в роли холста

// для рисования, поэтому мы присваиваем его переменной с именем canvas.

var canvas:BitmapData = new BitmapDatadOO, 100, false, OxFFFFFFFF);

// Переносим векторное изображение прямоугольника на растровое изображение canvas. draw(rect);

// Переносим векторное изображение эллипса на растровое изображение. // Используем матрицу преобразования, чтобы поместить эллипс в точку // с координатой (10, 10) внутри объекта BitmapData. var matrix:Matrix = new Matrix( ); matrix. translatedO, 10); canvas. draw(ellipse, matrix);

// Связываем объект BitmapData с объектом Bitmap, чтобы отобразить его // на экране

var bmp;Bitmap = new Bitmap(canvas); addChild(bmp);

На рис. 26.7 показано растровое изображение, полученное в результате выполнения предыдущего кода, с увеличенным масштабом для более тщательного рассмотрения. Обратите внимание, что среда выполнения Flash сглаживает края эллипса, поэтому он смешивается с существующим прямоугольником.

Руководство по actionscript. часть 5, стр. 049

Сглаживание содержимого, переносимого в объект BitmapData, происходит по отношению к существующему фону в растровом изображении.

Далее мы воспользуемся методом draw ( ) для выполнения растеризации объекта TextField, чтобы можно было применить к нему эффект растворения на уровне пикселов. Этот код представлен в листинге 26.9.

Рис. 26.7. Отображаемые объекты, объединенные в растровом изображении

Листинг 26.9. Растеризация и последующее растворение объекта TextField

package { import flash. display.*; import flash. utils.*; import flash. events.*; import flash. geom.*; import flash. text.*;

public class DissolveText extends Sprite { // Переменные, используемые для эффекта растворения private var randomSeed:int = Math. floor(Math. random( ) * int. MAX_VALUE);

private var destPoint:Point = new Point(0, 0); private var numberOfPixels:int = 10; private var destColor:uint = OxFFOOOOOO;

// Объект, в который будет переноситься текст private var bitmapData.-BitmapData;

// Таймер, используемый для периодического вызова метода pixelDissolve( ) private var t:Timer;

// Конструктор

public function DissolveText ( ) { // Создаем текст

var txt:TextField = new TextField( ); txt. text = «Essential ActionScript 3.0″; txt. autoSize = TextFieldAutoSize. LEFT; txt. textColor = OxFFFFFF;

// Создаем объект BitmapData с размерами, // достаточными для размещения текста

bitmapData = new BitmapData(txt. width, txt. height, false, destColor); // Переносим текст в объект BitmapData bitmapData. draw(txt);

// Связываем объект BitmapData с объектом Bitmap, чтобы отобразить его // на экране

var bitmap:Bitmap = new Bitmap(bitmapData); addChild(bitmap);

// Начинаем периодически вызывать метод pixelDissolve( ) t = new Timer(lO);

t. addEventLi stener(TimerEvent. TIMER, ti merLi stener); t. start( );

}

// Обрабатывает события TimerEvent. TIMER private function timerListener (e:TimerEvent):void { dissolve( );

}

// Выполняет растворение public function dissolve( ):void { // Вызываем метод pixelDissolve( ), чтобы растворить указанное // количество пикселов, и запоминаем возвращенное псевдослучайное // число для следующего раза. Использование возвращаемого // псевдослучайного числа гарантирует плавное растворение. randomSeed = bitmapData. pixelDissolve(bitmapData,

bitmapData. rect,

destPoint,

randomSeed,

numberOfPixels,

destColor);

// Прекращаем растворение, когда все пикселы будут иметь целевой цвет // (то есть когда ширина и высота области, в которой отсутствует // целевой цвет, будут равны 0) var coloredRegion:Rectangle =

bitmapData. getColorBoundsRect(OxFFFFFFFF, destColor, false): if (coloredRegion. width == 0 && coloredRegion. height == 0 ) { t. stop( ):

}

}

}

}

Метод draw ( ) также используется для растеризации векторного содержимого с целью повышения производительности. Например, вспомните простую программу рисования ScribbleAS3, представленную ранее в листинге 26.6. Она рисует точки всякий раз, когда происходит перемещение мыши, но не соединяет нарисованные точки линиями. Одним из способов соединить точки является использование метода экземпляра 1 ineTo ( ) класса Graphics, который рисует векторную линию между двумя точками. Тем не менее применение векторов для рисования линий ограничивает производительность: теоретически можно нарисовать такое количество линий, которое не позволит приложению реагировать на действия пользователя (из-за ограничений в механизме отображения векторов среды выполнения Flash). Для решения этой проблемы мы можем рисовать линии с помощью метода 1 ineTo ( ) в экземпляре класса Shape, не отображаемом на экране. После рисования каждой линии мы копируем ее из объекта Shape в объект BitmapData, после чего очищаем данный экземпляр класса Shape. Поскольку за один раз рисуется только одна векторная линия, приложение никогда не прекратит реагировать на действия пользователя.

Руководство по actionscript. часть 5, стр. 050

В листинге 26.10 продемонстрирован код, часть которого вам знакома из листинга 26.6. Обратите особое внимание на метод drawLine ( ), который выделен полужирным шрифтом.

Листинг 26.10. Приложение ScribbleAS3, версия с не отображаемыми на экране векторами

package { import flash. display.*; import flash. events.*; import flash. ui.*; import flash. geom.*;

// Простое приложение для рисования. В данной версии вектор рисуется // за пределами экрана, после чего он копируется на поверхность растрового // изображения, исключая снижение производительности, которое связано // с рисованием слишком большого количества векторов, public class ScribbleAS3_VectorV2 extends Sprite { private var canvas:Bitmap; // Холст растрового изображения,

// отображаемого на экране private var virtual Canvas:Shape; // Холст векторного изображения.

// не отображаемого на экране private var canvasContai ner:Sprite: // Содержит растровое изображение.

// обеспечивая интерактивность

private var isDrawing:Boolean = false; // Сообщает о том, нажата ли

// кнопка мыши в настоящий момент private var border:Shape; // Линия вокруг растрового изображения private var lastX:int; // х-координата последней точки,

// в которой щелкнул кнопкой мыши пользователь private var lastYrint; // у-координата последней точки,

// в которой щелкнул кнопкой мыши пользователь

// Конструктор

public function ScribbleAS3_VectorV2 ( ) { createCanvas( ); registerForInputEvents( );

// Предотвращаем изменение размеров окна приложения stage. scaleMode = StageScaleMode. N0_SCALE;

}

// Создает холст растрового изображения, отображаемого на экране,

// и холст векторного изображения, не отображаемого на экране

private function createCanvas (width:int = 200, height:int = 200):void {

// Создаем новый объект, не отображаемый на экране, в котором будет

// происходить рисование векторных линий перед их переносом

// в объект canvasData

virtual Canvas = new Shape( );

// Определяем объект данных, который будет хранить реальные пиксельные

// данные для рисунка пользователя. Линии копируются из объекта

// virtual Canvas в данный объект.

Руководство по actionscript. часть 5, стр. 051

Var canvasData:BitmapData = new BitmapData(width,

height, false. OxFFFFFFFF);

// Создаем новый отображаемый объект Bitmap, используемый // для отображения объекта canvasData canvas = new Bitmap(canvasData);

// Создаем объект Sprite, который будет содержать объект Bitmap. Класс // Bitmap не поддерживает пересылаемые события ввода, поэтому помещаем его // в объект Sprite, чтобы пользователь мог взаимодействовать с этим объектом. canvasContainer = new Sprite( ); canvasContainer. addChild(canvas);

// Добавляем экземпляр canvasContainer класса Sprite (и содержащийся // в нем объект Bitmap) в иерархию отображения данного объекта addChi1d(canvasContai ner);

// Создаем границу вокруг области рисования.

border = new ShapeC );

border. graphi cs.1i neSty1e(1);

border. graphics. drawRect(0. 0, width, height);

addChild(border);

// Регистрирует приемники для необходимых событий мыши и клавиатуры private function registerForlnputEvents ( ):void { // Регистрируем приемники для событий нажатия кнопки мыши // и перемещения мыши от объекта canvasContainer canvasContai ner. addEventLi stener(MouseEvent. MOUSEJDOWN.

Руководство по actionscript. часть 5, стр. 052

MouseDownListener); canvasContai ner. addEventLi stener(MouseEvent. M0USE_M0VE,

mouseMoveListener);

// Регистрируем приемники для событий отпускания кнопки мыши и нажатия

// клавиши от объекта Stage (то есть для глобальных событий).

// Используем объект Stage, поскольку событие отпускания кнопки мыши

// должно всегда завершать рисование, даже если указатель мыши

// не находится над областью рисования. Подобным образом, нажатие

// пробела должно всегда приводить к стиранию рисунка, даже когда

// объект canvasContainer не имеет фокуса.

stage. addEventLi stener(MouseEvent. MOUSEJJP, mouseUpLi stener);

stage. addEventLi stener(KeyboardEvent. KEYJDOWN, keyDownLi stener);

}

// Устанавливает цвет указанного пиксела. Используем этот способ

// для рисования одиночного пиксела, поскольку метод Graphics. lineTo( )

// не рисует одиночные пикселы

public function drawPoint (х:int, y:int. color:uint = OxFFOOOOOO):void { // Устанавливаем цвет указанного пиксела canvas. bitmapData. setPixel(х. у, color);

}

// Рисует векторную линию в объекте virtual Canvas, а затем копирует // растровое представление этой линии в объект canvasData (доступ // к растровому представлению осуществляется через переменную // canvas. bitmapData)

public function drawLine (xl:int, yl:int, x2:int, y2:int,

col or:uint = OxFFOOOOOO):void { // Рисуем линию в объекте virtual Canvas virtualCanvas. graphics. clear( ); virtual Canvas, graphics. lineStyled, 0×000000, 1, true,

LineScaleMode. NORMAL, CapsStyle. NONE); vi rtualCanvas. graphi cs. moveTo(xl, yl); vi rtualCanvas. graphi cs.1i neTo(x2, y2); // Копируем линию в объект canvasData canvas. bitmapData. draw(vi rtualCanvas);

}

// Отвечает на события MouseEvent. MOUSEJDOWN

private function mouseDownListener (e:MouseEvent):void {

// Устанавливаем флажок, указывающий на то, что основная кнопка мыши

// в настоящий момент нажата

isDrawing = true;

// Запоминаем точку, в которой щелкнул пользователь, чтобы в случае // перемещения мыши мы могли нарисовать линию из этой точки lastX = e. localX;

lastY = е. localY;

// Рисуем точку в позиции, где произошел щелчок кнопкой мыши drawPoint(e. localX, е. localY);

}

// Отвечает на события MouseEvent. M0USE_M0VE

private function mouseMoveListener (e:MouseEvent):void {

// Рисуем линию, когда мышь перемещается над областью рисования

// при нажатой основной кнопке мыши

if (isDrawing) {

// Используем переменные 1ocalX и localY, чтобы получить позицию // указателя относительно объекта canvasContainer. var thisX:int = e. localX; var thisY:int = e. localY;

// Рисуем линию в новую позицию указателя мыши drawLinedastX. lastY, thisX, thisY);

// Запоминаем последнюю позицию указателя мыши // для следующего раза lastX = thisX; lastY = thisY;

// Обновляем экран сразу после завершения выполнения // данной функции-приемника события е. updateAfterEvent( );

}

// Отвечает на события MouseEvent. MOUSEJJP

private function mouseUpListener (e:MouseEvent):void {

// Устанавливаем флажок, указывающий на то, что в настоящий момент

// основная кнопка мыши отпущена

isDrawing = false;

}

// Отвечает на события KeyboardEvent. KEYJDOWN private function keyDownListener (e:KeyboardEvent):void { // Стираем рисунок, когда пользователь нажимает клавишу Пробел. // Чтобы очистить рисунок, мы присваиваем всем пикселам // значение белого цвета, if (е. charCode == Keyboard. SPACE) { canvas. bitmapData. fillRect(new Rectangle(0. 0,

canvas. width, canvas. height),

OxFFFFFFFF);

}

}

}

}

Как метод draw( ) использует значения канала Alpha. Когда прозрачный объект-источник BitmapData копируется в прозрачный целевой объект BitmapData

с помощью метода draw ( ), каналы Alpha двух объектов BitmapData объединяются вместе на уровне пикселов с использованием алгоритма режима смешения BlendMode. SCREEN, который записывается следующим образом:

(значениемрЬаИсходногоОбъекта * (2ЬЬ-значениеМр1лаЦелевого0бъекта) I 256) + значениеА 1р11аЦелевого0бъекта

Когда значения канала Alpha двух объединяемых объектов находятся в диапазоне от 1 до 254, результатом будет являться значение канала Alpha с большей непрозрачностью, чем любое из исходных значений канала Alpha. Если объединяемый источник является полностью прозрачным, целевой объект BitmapData сохраняет свое исходное значение канала Alpha. Если целевой объект является полностью прозрачным, его значение канала Alpha заменяется значением канала Alpha объекта-источника.

Руководство по actionscript. часть 5, стр. 053

Чтобы полностью заменить значения канала Alpha в целевом объекте BitmapData значениями объекта-источника BitmapData (вместо объединения двух значений), используйте метод copyPixels ( ) вместо метода draw ( ). Дополнительную информацию можно найти в подразд. «Метод экземпляра copyPixels( ) класса BitmapData» данного раздела.

Невозможность произвольного захвата изображения экрана. Стоит отметить, что в ActionScript невозможно захватить изображение экрана в произвольной прямоугольной области. Язык ActionScript позволяет лишь преобразовывать отображаемые объекты в растровый формат. В ActionScript ближайшим аналогом операции захвата изображения области отображения является использование экземпляра класса Stage в качестве параметра источник метода draw ( ), как показано в следующем коде:

var canvas:BitmapData = new BitmapDatadOO. 100, false. OxFFFFFFFF); canvas Ага^(некий0бьект01spl ayObject. stage);

Здесь некий0бъектй1spl ayObject — это экземпляр класса DisplayObject, находящийся в списке отображения. Предыдущий код создает растровое изображение, содержащее все объекты, которые в настоящий момент находятся в списке отображения, со следующими оговорками:

? цвет фона SWF-файла не копируется в растровое изображение;

? если доступ к объектам, находящимся в списке отображения, запрещен из-за ограничений безопасности, они не копируются в растровое изображение и генерируется исключение SecurityError.

Метод экземпляра copyPixelst) класса BitmapData

Как и draw ( ), метод copyPixels ( ) применяется для копирования значений цвета пикселов из объекта-источника в целевой объект BitmapData. Однако в отличие от метода draw ( ), который копирует пиксельные данные из любого экземпляра класса DisplayOb j ect или объекта BitmapData, метод copyPixels ( ) может копировать их только из объектов BitmapData. Этот метод отличается производительностью и удобством использования. Тестирование показывает, что операции copyPixels ( ) быстрее эквивалентных операций draw ( ) на 25-300 %.

I Чтобы достичь максимальной производительности при копировании значений цвета м?’ 4 „ пикселов между двумя объектами BitmapData, используйте метод copyPixels() вместо *Ц’ метода draw().

Помимо того что метод copyPixels ( ) производительнее метода draw ( ), он предоставляет разработчику простой доступ к таким операциям, как:

? размещение пикселов из объекта-источника в определенной точке объекта-получателя;

? объединение канала Alpha одного растрового изображения с каналом Alpha другого растрового изображения;

? перезапись значений канала Alpha целевого растрового изображения при копировании в него пикселов из исходного растрового изображения.

Руководство по actionscript. часть 5, стр. 054

Хотя все три перечисленные операции также могут быть реализованы с помощью метода draw ( ) совместно с другими методами класса BitmapData, метод copyPixels ( ) обычно предпочтителен благодаря его удобству.

Метод copyPixels ( ) имеет следующий вид:

целевойОбъектШtmapData. copyPi xel s(исходныйОбъектШtmapData, исходнаяОбласть, целеваяТочка, обьектВ! tmapDataHaHanaA Ipha. точкаКаналаАIpha. обьединениеКаналовАIpha)

Здесь целевой0бъектВ1tmapData — это объект BitmapData, в который будут перенесены пикселы. Рассмотрим параметры метода draw ( ).

? исходный0бьектВ1 tmapData — экземпляр класса BitmapData, который будет скопирован в объект целевой0бъектВ1 tmapData. Объекты исходный0бъектВ1 tmapData и це-левой0бъектВ1tmapData могут являться одним объектом, позволяя копировать пикселы из одной области изображения в другую область того же изображения.

? исходнаяОбласть — объект Rectangle, определяющий область объекта исходный-0бьектВ1tmapData, которая будет скопирована в объект целевойОбъектВ! tmapData. Чтобы скопировать весь объект исходныйОбъектВт tmapData, используйте переменную исходныйОбъектВ! tmapData. rect. Если в функцию передается аргумент обьектВ1tmapDataKaнaлaAльфa, данный параметр также определяет ширину и высоту прямоугольной области внутри объекта объектВ! tmapDataKananaA Ipha, значения канала Alpha которой будут скопированы в объект целевойОбьект-BitmapData.

? целеваяТочка — объект Point, определяющий позицию левого верхнего угла прямоугольной области внутри объекта целевой0бьектВ1tmapData, в которую будут помещены копируемые пикселы.

? 06beKTBitmapDataKaHanaA Ipha — необязательный объект BitmapData, отличный от объекта исходныйОбъектВ! tmapData, значения канала Alpha которого станут новыми значениями канала Alpha пикселов, переносимых в объект целевой0бьектВ1 tmapData. Высота и ширина конкретной прямоугольной области, значения канала Alpha которой будут скопированы в объект целевойОбъектВ! tmapData, определяются параметром исходнаяОбласть.

С помощью этого параметра мы можем объединять RGB-каналы одного растрового изображения (исходныйОбъектШ tmapData) с каналом Alpha другого растрового изображения (oObeKTBitmapDataKaHanaA Ipha). Подобная методика может быть использована, например, для создания на фотографиях в электронном приложении, имитирующем альбом для наклеивания газетных вырезок, эффекта краев неправильной формы. Каждая фотография могла бы храниться в своем собственном объекте BitmapData, а края неправильной формы можно было бы хранить в виде значений канала Alpha в одном повторно используемом объекте BitmapData. С помощью параметра o6bet ? WHKaKaHanaAlpha — объект Point, определяющий левый верхний угол прямоугольной области внутри объекта объектВт tmapDataKaHanaA Ipha, из которой будут получены значения канала Alpha. Ширина и высота прямоугольной области задаются параметром исходнаяОбласть.

? объединениеКаналовА Ipha — значение типа Boolean, которое показывает, должны ли значения каналов Alpha объектов целевой0бъектВ1 tmapData и исходныйОбь-ектВ1 tmapData в процессе копирования данных объединяться (true), или значения канала Alpha объекта исходный0бъектВ1 tmapData должны полностью заменять существующие значения канала Alpha объекта целевойОбъектВ!’tmapData (false). Этот параметр оказывает влияние на результат только в том случае, когда оба объекта целевой0бьектВ1 tmapData и исходный0бъектВ1 tmapData являются прозрачными растровыми изображениями. Значением по умолчанию является false, указывающее, что значения канала Alpha объекта исходный0бъектВ1 tmapData полностью заменяют существующие значения канала Alpha объекта целевойОбъ-eKTBitmapData. Алгоритм, используемый для объединения значений каналов Alpha, соответствует алгоритму, рассмотренному ранее в подразд. «Метод экземпляра draw( ) класса BitmapData» данного раздела.

Руководство по 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. Исходное изображение показано слева, а изображение с «краями» — справа.



Полезные ссылки
Случайные записи
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 062
  • 19.03.2011">Руководство по actionscript. часть 2, стр. 093
  • 14.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.79
  • 12.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.111
  • 22.03.2011">Руководство по actionscript. часть 2, стр. 014
  • 04.06.2011">О дизайне веб-сайта
  • 04.03.2011">Руководство по actionscript. часть 5, стр. 039
  • 04.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.32
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 043
  • 23.02.2011">Руководство по actionscript. часть 7, стр. 024
  • 02.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.111
  • 10.08.2011">Samsung GT-S5250 – отличный помощник
  • 07.03.2011">Руководство по actionscript. часть 4, стр. 126
  • 06.03.2011">Руководство по actionscript. часть 4, стр. 134
  • 16.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.23
Опрос

Какие цвета вы предпочитаете?

View Results

Loading ... Loading ...