topical media & game development
#graphic-flex-image-effects-09-Flex-GrowingDistress.ax
#graphic-flex-image-effects-09-Flex-GrowingDistress.ax
[swf]
[flash]
flex
package {
import aether.utils.Adjustments;
import aether.utils.ImageUtil;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.BlendMode;
import flash.display.Sprite;
import flash.filters.BlurFilter;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
[SWF(width=600, height=300, backgroundColor=0x333333)]
Demonstrates how letters in a textfield can be separated into separate bitmap data instances
so that different effects may be applied to each. Here, each letter has a growing amount of
distress applied.
public class @ax-graphic-flex-image-effects-09-Flex-GrowingDistress extends Sprite {
Constructor. Creates textfield, draws each letter into separate bitmap data,
then distresses each letter individually.
public function @ax-graphic-flex-image-effects-09-Flex-GrowingDistress() {
var field:TextField = createField();
var letters:Vector.<BitmapData> = createLetterBitmaps(field);
distressLetters(letters);
}
Creates a textfield.
returns: The textfield created.
private function createField():TextField {
var field:TextField = new TextField();
// make sure you have Impact installed
field.defaultTextFormat = new TextFormat("Impact", 100, 0xFFFFFF);
field.autoSize = TextFieldAutoSize.LEFT;
field.text = "DISTRESS";
field.x = (stage.stageWidth - field.width)/2;
field.y = (stage.stageHeight - field.height)/2;
return field;
}
Draws each letter in textfield into separate bitmap data and returns
these references in a vector.
parameter: field The textfield with text to draw into bitmap data instance.
returns: A vector of BitmapData instances where each instance holds the pixel
data from a single letter.
private function createLetterBitmaps(field:TextField):Vector.<BitmapData> {
// draw entire field into bitmap data
var bitmapData:BitmapData = ImageUtil.getBitmapData(field);
var letters:Vector.<BitmapData> = new Vector.<BitmapData>();
var text:String = field.text;
var numLetters:uint = field.text.length;
// will be used to center vertically
var halfHeight:Number = field.height/2;
// the placement of the first letter
var startX:Number = field.x;
// the vertical middle of the field
var y:Number = field.y + halfHeight;
var x:Number;
var letterData:BitmapData;
var bitmap:Bitmap;
var sprite:Sprite;
var bitmapWidth:Number;
for (var i:uint = 0; i < numLetters; i++) {
// create a sprite to hold each bitmap
sprite = new Sprite();
// place the single letter being evaluated into the field
field.text = text.charAt(i);
// draw the single letter into bitmap data
letterData = ImageUtil.getBitmapData(field);
bitmap = new Bitmap(letterData);
// find width of letter
bitmapWidth = bitmap.width;
// center the letter horizontally on the bitmaps registration point
bitmap.x = -bitmapWidth/2;
// center the letter vertically on the bitmaps registration point
bitmap.y = -halfHeight;
// place all the text up to and including this letter into field
field.text = text.substr(0, i+1);
// based on field's current length and width of bitmap, place letter
x = startX + field.width - bitmapWidth;
sprite.x = x + bitmapWidth/2;
sprite.y = y;
// add bitmap to sprite and sprite to stage;
// the nesting is done so that the sprite may be transformed with the bitmap centered within it
sprite.addChild(bitmap);
addChild(sprite);
// push data into vector
letters.push(letterData);
}
return letters;
}
Distresses each bitmap data instance in the vector separately, with each
letter getting more distressed than the previous.
parameter: letters A vector of bitmap data to distress.
private function distressLetters(letters:Vector.<BitmapData>):void {
for (var i:uint = 1; i < letters.length; i++) {
distressImage(letters[i], i*3);
// rotate the image to apply same distortion in opposite directions
rotateImage(letters[i]);
distressImage(letters[i], i*3);
// rotate image back right side up
rotateImage(letters[i]);
}
}
Draws a copy of the image, rotated 180 degrees, into the original image.
parameter: bitmapData The image to rotate.
private function rotateImage(bitmapData:BitmapData):void {
var matrix:Matrix = new Matrix();
// PI radians == 180 degress
matrix.rotate(Math.PI);
matrix.translate(bitmapData.width, bitmapData.height);
var rotatedBitmap:BitmapData = new BitmapData(bitmapData.width, bitmapData.height, true, 0x00000000);
rotatedBitmap.draw(bitmapData, matrix);
// copy rotated data into original bitmap data
bitmapData.copyPixels(rotatedBitmap, bitmapData.rect, new Point());
}
Applies distress effects to the specified image at the specified amount.
parameter: bitmapData The image to distress
parameter: amount The amount to distress the image. This should be somethig between 0 and 20, ideally.
private function distressImage(bitmapData:BitmapData, amount:Number):void {
// Perlin noise that will be used for displacement
var perlin:BitmapData = new BitmapData(bitmapData.width, bitmapData.height);
perlin.perlinNoise(
10,
10,
5,
Math.random(),
true,
true,
BitmapDataChannel.RED
);
// create more light than dark in the noise
Adjustments.setLevels(perlin, 0, 50, 100);
var displaceX:Number = amount;
// displacing more vertically works better for maintaining text legibility
var displaceY:Number = amount*3;
ImageUtil.applyFilter(
bitmapData,
new DisplacementMapFilter(
perlin,
new Point(),
BitmapDataChannel.RED,
BitmapDataChannel.RED,
displaceX,
displaceY,
DisplacementMapFilterMode.WRAP
)
);
// this noise will be used to alter opacity of distressed image with transparent speckles
var noise:BitmapData = new BitmapData(bitmapData.width, bitmapData.height);
noise.noise(Math.random(), 0, 255, BitmapDataChannel.RED, true);
// apply blur to noise
ImageUtil.applyFilter(noise, new BlurFilter(displaceX, displaceY));
// really reduce contrast of noise
Adjustments.setLevels(noise, 105, 107, 109);
// draw a grayscale image of the distressed image's alpha channel
var alpha:BitmapData = ImageUtil.getChannelData(
bitmapData,
BitmapDataChannel.ALPHA
);
// apply the noise to the grayscale alpha channel image using multiply
alpha.draw(
noise,
null,
new ColorTransform(
1,
1,
1,
Math.min(1, amount*.2)
),
BlendMode.MULTIPLY
);
// copy the altered grayscale image into the alpha channel of the distressed image
bitmapData.copyChannel(
alpha,
alpha.rect,
new Point(),
BitmapDataChannel.RED,
BitmapDataChannel.ALPHA
);
}
}
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.