topical media & game development

talk show tell print

#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.