text: The a quick workaround that will allow you to crop multiple faces within an image. We'll create editable tags that a user can adjust after loading an image into the application.
  Final Result Preview
  Let's take a look at the final result we will be working towards:
  Upload an image, and the demo will show you which areas the Face Recognition Library recognises as faces. (It's not always perfect!)
  Since this is just a demo, there are a few restrictions: make sure you pick a landscape-oriented photo, and don't pick one with a large filesize. Of course, when you use this library in your own projects, you can work around these restrictions.
  Need photos to test this on? Try Flickr!
  Prerequisites
  Download the FaceRecognitionLib.swc from the library's project page. You will also need the face.zip file from the project's supervision. Navigate to. Click View raw file to download it.
  You'll need the Flex SDK (version 3.5 or later) and must have Flash Professional CS5 configured to target compilation for Flash Player 10 or later. The last thing you will need is the latest version of TweenLite, which we'll be using to add simple animations to our application.
  Step 1: Setting Up Flash
  Open Flash CS5 Professional and create a new Actionscript 3.0 file.
  Set the document class name to FaceTagger.
  Click ActionScript Settings in the Properties panel. Click on the Library path tab in the ActionScript Settings window. Browse to the FaceRecognitionLib.swc to add it to the project. Repeat this process for the greensock.swc file.
  Step 2: Add Color to the Stage
  Click on the Stage. Change the Stage's color to a color of your choice.
  Step 3: Create the Main Buttons
  Open the Components panel. Drag a button onto the top right corner of the stage.
  Set the instance name of the button to
  browseBtn in the Properties panel. Within the Component Parameters panel, change the button's label to Browse.
  Add another button to the stage directly to the left of
  browseBtn. Change the label of the button to Add Tag and set its instance name to
  addBtn.
  Step 4: Create the Remove Button
  When our application detects a face, a tag that will appear over the cropped face will be generated. It will contain a button that will remove the tag when it is clicked. The tag itself will be drawn entirely with code but we need to draw the button that will remove the tag within manually.
  Using the Oval tool (press the O key to switch to the oval tool), add an oval to the stage that is 36 pixels tall and 36 pixels wide (you can alt-click the stage to bring up a dialog for this). The oval should have a stroke of 2.0 and have a White line color and Dark Grey fill color as seen below.
  Note: In this image, the layers containing our two buttons are locked and hidden. Do not remove them from the stage.
  Using the Line tool (press the N key to switch to the line tool), draw a diagonal line on the stage while holding the shift key to give the line a fixed angle. Paste a copy of the line to the stage. In the top menu of Flash, select Modify, scroll down to Transfrom and select Flip Horizontal. Align the new line on top of the original line to form an X shape.
  Drag both lines onto the oval shape. Select the oval shape along with each line. Press F8 to open the Convert to Symbol window. Set the name of the symbol to RemoveButton and the type to Movie Clip. Make sure the registration is set to the top left and that the folder is set to library root. Under the Advanced options, check Export for ActionScript. The Class field should read RemoveButton and the base class should
  flash.display.MovieClip. Click OK to create the symbol. An instance of the
  RemoveButton class doesn't need to exist at runtime. We will instantiate it when we need to, using code, so you can remove it from the
  Stage.
  Step 5: Our First Code
  If you remember from Step 1, the FaceTagger class is our document class. Most of the magic will happen in this class.
  Create a new class and name it FaceTagger. The class should extend the
  flash.display.Sprite class.
  Let's begin by importing the following classes:; public class FaceTagger extends Sprite {
  Create the following variables and constants after the class declaration.
  private var statusTxt:TextField; private var fileRef:FileReference; private var fileFilter:FileFilter; private var loader:Loader; private var darkBox:Sprite; private var bitmap:Bitmap; private var image:MovieClip; public static const MIN_WIDTH:Number = 50; public static const MIN_HEIGHT:Number = 50; public static const MAX_WIDTH:Number = 1000; public static const MAX_HEIGHT:Number = 1000; public static const FILE_TYPES:String = "*.jpg; *.jpeg; *.png";
  We need a
  TextField object to display messages to the user. The
  FileReference object allows the user to upload an image from the computer and the
  FileFilter object limits the file types the user can upload. The
  Loader object is needed to actually parse the image's data from the
  FileReference object. The
  darkBox variable is a
  Sprite that will be used to darken the screen when a tag is being edited. We'll do this to add contrast to our application. Doing so will let the user know that they are in some kind of Edit mode when the screen is dark and the current tag is in focus. Finally we'll need a
  Bitmap object to represent the actual image and a
  MovieClip to contain the bitmap image and all of the image's tags.
  MIN_WIDTH and
  MIN_HEIGHT represent the minimum demensions that the users image should be in order for the face detection process to occur.
  MAX_WIDTH and
  MAX_HEIGHT represent the maximum demensions.
  FILE_TYPES holds the file types that we will allow the user to choose from when they're loading an image into our application.
  Let's add some code to the class constructor.
  public function FaceTagger() { statusTxt = new TextField(); fileRef = new FileReference(); fileFilter = new FileFilter( "Image (" + FILE_TYPES + ")", FILE_TYPES ); loader = new Loader(); darkBox = new Sprite(); init(); }
  We pass two parameters into the
  FileFilter contructor. The first parameter is string that contains the description of the filter which in this case is an image. We pass the
  FILE_TYPES constant within parentheses to display the allowed file types to the user when they are browsing for an image to load. The second parameter is a
  String that contains the allowed file types. We pass our
  FILE_TYPES constant into this parameter as will. Lasly, we call the
  init method which we will create later, to initialize the application.
  Step 6: Initializing the Display
  Let's create the
  init method.
  private function init():void { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addEventListener( Event.RESIZE, onStageResize ); browseBtn.addEventListener( MouseEvent.CLICK, browse ); addBtn.addEventListener( MouseEvent.CLICK, addTag ); fileRef.addEventListener( Event.SELECT, onFileSelected ); fileRef.addEventListener( Event.COMPLETE, onFileComplete ); loader.contentLoaderInfo.addEventListener( Event.COMPLETE, detectFaces ); statusTxt.type = TextFieldType.DYNAMIC; statusTxt.selectable = false; statusTxt.autoSize = TextFieldAutoSize.CENTER; statusTxt.defaultTextFormat = new TextFormat( null, 22, 0xFFFFFF, true ); statusTxt.text = "Choose an image to upload"; statusTxt.filters = [ new DropShadowFilter( 5, 45, 0, 1, 5, 5, 1, 3 ) ]; darkBox.graphics.beginFill( 0, .5 ); darkBox.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight ); darkBox.visible = false; darkBox.addEventListener( MouseEvent.CLICK, exitEditMode ); addChild( statusTxt ); addChild( darkBox ); positionContents(); }
  We initialize the
  stage by setting its
  align property to TOP_LEFT and setting its scaleMode property to NO_SCALE. We call the
  onStageResize method when the
  stage is resized. We call the
  browse method, which will allow the user to browse images to load, when
  browseBtn has been clicked.
  The
  addTag method is called when a user clicks
  addBtn. We need to listen for when the user selects a file so that we can load the file into memory. We also listen for when the file has been loaded and when the
  Loader object has finished parsing the loaded data into an image.
  We initialize our textfield and apply a nice drop shadow filter to add depth to our text. Finally we draw graphics to the
  darkBox object, display the textfield, and we call the
  positionContents method which we will now create.
  private function positionContents():void { browseBtn.x = stage.stageWidth - browseBtn.width - 10; addBtn.x = browseBtn.x - addBtn.width - 10; statusTxt.x = ( stage.stageWidth - statusTxt.width ) / 2; statusTxt.y = stage.stageHeight - statusTxt.height - 10; darkBox.width = stage.stageWidth; darkBox.height = stage.stageHeight; if ( image ) { image.x = ( stage.stageWidth - image.width ) / 2; image.y = ( stage.stageHeight - image.height ) / 2; } }
  The
  positionContents method is self-explanatory. It positions each element based on the size of the stage. We resize the
  darkBox object to the size of the
  stage and only position the
  image object if it exists.
  We want to call the
  positionContents method every time the
  stage is resized. Create the method
  onStageResize to handle this:
  private function onStageResize( e:Event ):void { positionContents(); }
  Step 7: Loading an Image
  In order to look for faces within an image, we need an image in our possession. Let's create the
  browse method.
  private function browse( e:MouseEvent ):void { fileRef.browse( [ fileFilter ] ); }
  We simply call the
  FileReference object's
  browse method and this opens a native window which allows the user to browse for an image file. We need to apply our
  FileFilter object to limit the file types that the user can browse. We pass the filter into the first parameter of the
  browse method within an
  Array object to accomplish this.
  Now the user can browse for an image to load. We'll have to load the file into Flash when the user selects a file. For this, let's create the
  onFileSelected method. This method is an event handler function that is called when the user selects a file.
  private function onFileSelected( e:Event ):void { browseBtn.enabled = false; statusTxt.text = "loading"; fileRef.load(); }
  We listened for the
  SELECTED event in the
  init method. We also listened for the
  COMPLETE event on the which is dispatched by the
  contentLoaderInfo object when the image data has been parsed. The
  onFileComplete method is called when this event occurs. Let's create this method also.
  private function onFileComplete( e:Event ):void { loader.loadBytes( fileRef.data ); }
  First thing we want to do once a file has been selected is disable the Browse button so that the user can't load a second file. We display the status to the user and finally we call the
  load method from the
  FileReference object. This loads the selected file into memory.
  The
  onFileComplete method simply tells the
  Loader object to parse the bytes of the loaded file. We previously listened for
  loader.contentLoaderInfo to dispatch a
  COMPLETE event. When this event is dispatched the
  detectFaces method is called. Let's start coding this method.
  private function detectFaces( e:Event ):void { bitmap = Bitmap( loader.content ); addChild( bitmap); }
  For now we will only assign a reference to
  loader.content to our
  Bitmap object. We use type casting to tell Flash to treat
  loader.content as a
  Bitmap object, and then finally we display the image.
  Step 8: Handling the Loaded Image
  Before we can start the face detection process, we need to make sure that the demensions of the uploaded image are within a range for accurate face detection. If an image is to large it can cause our application too crash when we scan the image for faces. If the image is too tiny, the chances of the
  FaceDetector object not being able to detect a face within an image that actually has a face increases. We need to set limits here.
  Let's create a static method called
  inRange.
  private static function inRange( width:Number, height:Number ):Boolean { if ( width < MIN_WIDTH || width > MAX_WIDTH ) { return false; } else if ( height < MIN_HEIGHT || height > MAX_HEIGHT ) { return false; } else { return true; } }
  The
  inRange method returns
  true if the specified width and height are not out of range. It returns
  false otherwise. We are going to call this method in the
  detectFaces method. Remove the line
  "addChild( bitmap );" from the
  detectFaces method. Then add the following lines of code.
  if ( !inRange( bitmap.width, bitmap.height ) ) { if ( !image ) image = new MovieClip(); image.addChild( bitmap ); addChildAt( image, 0 ); image.alpha = 0; TweenLite.to( image, 1, { alpha:1 } ); statusTxt.text = "image too large for face detection"; return; }
  Also we need to add
  com.greensock.TweenLite to the class path.
  import com.greensock.TweenLite;
  We pass the
  width and
  height of the
  Bitmap object into the parameters of the
  inRange method. If the
  inRange method returns
  false, we instantiate the
  image object, add
  bitmap to the
  image object and display the image underneath the user interface. The image fades in using TweenLite and we display an error message to the user that the image is out of range. Finally, we exit out of the function using a
  return statement since we don't want the code that will follow the
  if statement to execute.
  Now that we have checked to see if the image is in a safe range for face detection we can now start detecting faces.
  Step 9: Using the FaceDetector Class
  Include the following classes in the FaceTagger classpath.
  com.oskarwicha.images.FaceDetection.FaceDetector
  com.oskarwicha.images.FaceDetection.Events.FaceDetectorEvent
  import com.oskarwicha.images.FaceDetection.FaceDetector; import com.oskarwicha.images.FaceDetection.Events.FaceDetectorEvent;
  Create a new variable underneath the class declaration named
  detector. The
  detector object should be of type
  FaceDetector. The beginning of the
  FaceTagger class should now look as follows.; import com.greensock.TweenLite; import com.oskarwicha.images.FaceDetection.FaceDetector; import com.oskarwicha.images.FaceDetection.Events.FaceDetectorEvent;; public static const MIN_WIDTH:Number = 50; public static const MIN_HEIGHT:Number = 50; public static const MAX_WIDTH:Number = 1000; public static const MAX_HEIGHT:Number = 1000; public static const FILE_TYPES:String = "*.jpg; *.jpeg; *.bmp; *.png"; public function FaceTagger() {
  Add the following lines of code to the
  detectFaces method.
  statusTxt.text = "detecting faces... please wait"; detector.addEventListener( FaceDetectorEvent.FACE_CROPED, onFacesDetected ); detector.addEventListener( FaceDetectorEvent.NO_FACES_DETECTED, onNoFaces ); detector.loadFaceImageFromBitmap( bitmap );
  First we add event listeners to the
  FaceDetector. There are two events that we need to listen for. The
  FACE_CROPED event and the
  NO_FACES_DETECTED event.
  (Note:
  FACE_CROPED is not a typo. It is likely a spelling mistake by the author of the library.)
  We want to call the
  onFacesDetected method whenever a face has been detected and the
  onNoFaces method whenever no faces were detected on the image. The last line of code loads the face image from our
  bitmap object containing the loaded image. We call the
  FaceDetector object's
  loadFaceImageFromBitmap method using the
  bitmap object as the parameter
  Bitmap that the method calls for.
  Step 10: Detecting Multiple Faces
  When the
  FaceDetector object's
  objectDetector detects faces in an image, the
  FaceDetector itself only crops one of those faces. If we want access to all of the detected faces we'll have to directly access the
  objectDetector. Create the
  onFacesDetected method and the
  onNoFaces method containing the following lines of code.
  private function onFacesDetected( e:Event ):void { var faces:Array = detector.objectDetector.detected; if ( !image ) image = new MovieClip() else return; image.addChild( bitmap ); addChildAt( image, 0 ); positionContents(); image.alpha = 0; TweenLite.to( image, 1, { alpha:1 } ); statusTxt.text = ""; for each( var face:Rectangle in faces ) { trace( face ); var rect:Rectangle = face; newTag( rect ); } positionContents(); } private function onNoFaces( e:Event ):void { statusTxt.text = "no faces were detected"; if ( !image ) image = new MovieClip(); image.addChild( bitmap ); addChildAt( image, 0 ); positionContents(); image.alpha = 0; TweenLite.to( image, 1, { alpha:1 } ); }
  Let's take a look at the
  onFacesDetected method. The
  FaceDetector object's
  objectDetector contains an array of detected objects. These objects are
  Rectangle objects that each represent the location and size of each cropped face that was successfully found in the image.
  We assign it to the
  faces variable which is an
  Array. If the
  image object doesn't exist yet we need to instantiate it. If it exists, we need to exit the function because the code has already executed once. We execute the same code the we did in the
  detectFaces method to display the
  image using a fade in animation. Then we clear the textfield.
  The
  for each loop is used to iterate through each
  Rectangle in the
  faces array. When traced to the output panel, a detected face will look something like this:
  (x=30, y=30, w=123, h=123)
  The
  newTag method generates a new PhotoTag object to display on the image based on the parameter
  Rectangle object supplied. Before we can add a tag to the display, we'll need to first create our tag class. We'll create this class in the next step.
  In the
  onNoFaces method we repeat the process but this time after we display the image, we notify the user that no faces were detected in the loaded image.
  Step 11: Begin the PhotoTag Class
  Create a new class named
  PhotoTag that extends
  Sprite.
  Import the following classes to the
  PhotoTag class.
  import flash.display.Sprite; import flash.geom.Rectangle; import flash.events.Event; import flash.display.MovieClip; import flash.filters.DropShadowFilter; import flash.events.MouseEvent; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import com.greensock.TweenLite;
  Create the following variables and constants.
  private var _rectangle:Rectangle; private var _image:MovieClip; private var _editMode:Boolean; private var _removed:Boolean; private var removeBtn:RemoveButton; public static const LINE_THICKNESS:Number = 6; public static const LINE_COLOR:uint = 0x00CCFF; public static const FILL_COLOR:uint = 0xFFFFFF; public static const ELLIPSE_WIDTH:Number = 10; public static const ELLIPSE_HEIGHT:Number = 10; public static const INIT_ALPHA:Number = .6;
  Add the following code to the class contructor.
  public function PhotoTag( rectangle:Rectangle, image:MovieClip ) { _rectangle = rectangle; _image = image; removeBtn = new RemoveButton(); graphics.lineStyle( LINE_THICKNESS, LINE_COLOR ); graphics.beginFill( FILL_COLOR, .5 ); graphics.drawRoundRect( 0, 0, rectangle.width, rectangle.height, ELLIPSE_WIDTH, ELLIPSE_HEIGHT ); filters = [ new DropShadowFilter( 5, 45, 0, 1, 5, 5, 1, 3 ) ]; alpha = INIT_ALPHA; _editMode = false; addEventListener( Event.ADDED, onAdded ); }
  The class contructor accepts two parameters:
  - The first parameter is the
  rectangleobject that contains data about the cropped face.
  - The second parameter is the
  MovieClipthat contains the uploaded bitmap image.
  We assign these to variables so that we can reference them throughout our code.
  On the next line a new instance of the
  RemoveButton class is created. Use the inherited
  graphics object to draw a rounded rectangle that is the size of the
  Rectangle object's
  width and
  height. The rectangle's ellipse width and height come from the class constants as well as the rectangle's line attributes. We apply a drop shadow filter to add depth to the object and set the
  alpha to the constant
  INIT_ALPHA (the initial alpha).
  _editMode is a property that tells us whether or not the tag is in an editable state.
  The last line in the contructor listens for the
  ADDED event then calls the
  onAdded method once the tag has been added to the display list. We do this because we'll need to access the
  stage object which is currently
  null. Once the object has been added we can safely access the
  stage.
  private function onAdded( e:Event ):void { removeEventListener( Event.ADDED, onAdded ); init(); }
  The
  onAdded method is called when the object is added to the display list. The event listener is no longer needed so it is removed and the
  init method is called.
  Step 12: Initializing the Photo Tag
  Create the
  init method in the
  PhotoTag class.
  private function init():void { if ( this.parent != image ) _image.addChild( this ); x = _rectangle.x; y = _rectangle.y; addChild( removeBtn ); removeBtn.alpha = 0; doubleClickEnabled = true; addEventListener( MouseEvent.ROLL_OVER, overState ); addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown ); stage.addEventListener( MouseEvent.MOUSE_WHEEL, onMouseWheel ); stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyDownE ); removeBtn.addEventListener( MouseEvent.CLICK, remove ); }
  The first line of code in the
  init method checks to see whether the tag was actually added to the
  image object. If it wasn't, the tag will add itself to the image.
  Next the tag's
  x and
  y are set to the
  rectangle's
  x and
  y. This simply positions the tag over the cropped face. By default, the
  removeBtn's
  alpha property is set to
  0 because we don't want it to be visible just yet. Later we will need to listen for a
  DOUBLE_CLICK event and the tag's
  doubleClickEnabled must be set to
  true in order for this event to be dispatched.
  The last five lines of code add event listeners to the tag, to the
  stage, and to the
  removeBtn.
  When the
  removeBtn is clicked we want to remove the tag from the display list. Create the
  remove method.
  private function remove( e:MouseEvent ):void { if ( this.parent ) { _removed = true; this.parent.removeChild( this ); } }
  The method removes the tag from its parent object, if it has one. We set the
  _removed property to
  true since the object is being removed.
  The
  _removed property is a private property but it needs to be accessed outside of the scope of this class. We only want to grant code, outside of the class, access to read the properties data. We also want to grant the same limited access to the
  _rectangle object, the
  _image object, and the
  _editMode property. Create the following getter methods.
  public function get rectangle():Rectangle { return _rectangle; } public function get image():MovieClip { return _image; } public function get editMode():Boolean { return _editMode; } public function get removed():Boolean { return _removed; }
  Now code outside of this class can access these objects through the getter methods. The methods can be treated as properties, so each property is effectively read only.
  Step 13: Adding Life to the PhotoTag Object
  If we want our
  PhotoTag objects to have a little life in them we'll need to add some interaction and animation. Add the following methods to the
  PhotoTag class.
  private function resize( percent:Number ):void { var newWidth:Number = ( percent * _rectangle.width ) / 100 + _rectangle.width; var newHeight:Number = ( percent * _rectangle.height ) / 100 + _rectangle.height; if ( newWidth < 60 ) { newWidth = 60; } if ( newHeight < 60 ) { newHeight = 60; } var newX:Number = ( x - image.x ) - ( newWidth - _rectangle.width ) / 2; var newY:Number = ( y - image.y ) - ( newHeight - _rectangle.height ) / 2; _rectangle.x = newX; _rectangle.y = newY; _rectangle.width = newWidth; _rectangle.height = newHeight; draw( newWidth, newHeight ); x = newX + image.x; y = newY + image.y; } private function overState( e:MouseEvent ):void { if ( _editMode ) return; removeEventListener( MouseEvent.ROLL_OVER, outState ); removeBtn.visible = true; removeBtn.alpha = 0; var percent:Number = 40; var newWidth:Number = ( percent * _rectangle.width ) / 100 + _rectangle.width; var newHeight:Number = ( percent * _rectangle.height ) / 100 + _rectangle.height; var newX:Number = _rectangle.x - ( newWidth - _rectangle.width ) / 2; var newY:Number = _rectangle.y - ( newHeight - _rectangle.height ) / 2; TweenLite.to( this, .1, { alpha:1, x:newX, y:newY, width:newWidth, height:newHeight } ); TweenLite.to( removeBtn, .1, { alpha:1 } ); addEventListener( MouseEvent.ROLL_OUT, outState ); } private function outState( e:MouseEvent ):void { if ( _editMode ) return; removeEventListener( MouseEvent.ROLL_OUT, outState ); TweenLite.to( this, .1, { alpha:INIT_ALPHA, x:_rectangle.x, y:_rectangle.y, width:_rectangle.width, height:_rectangle.height } ); TweenLite.to( removeBtn, .1, { alpha:1 } ); addEventListener( MouseEvent.ROLL_OVER, overState ); } private function onMouseWheel( e:MouseEvent ):void { if ( !_editMode ) return; var percent:Number = e.delta * 10; resize( percent ); } private function onKeyDownE( e:KeyboardEvent ):void { if ( !_editMode ) return; var percent:Number; if ( e.keyCode == Keyboard.UP ) { percent = 10; } else if ( e.keyCode == Keyboard.DOWN ) { percent = -10; } else { return; } resize( percent ); }
  It may look like a lot of code but what it actually accomplishes is quite simple; all of the methods basically execute the same code.
  Earlier we added an event listener for the
  ROLL_OVER event. We passed an event handler function to the
  eventHandler parameter called
  overState. This method adds a simple scale effect when the mouse hovers over the tag. The new width and height of the object is based on how much we want to increase the object's size by. In this case we want to increase the object's size by 40 percent.
  We could have stopped right here and simply used TweenLite to animate the object being resized but this wouldn't look very appealing because the object's registration is in the top left corner. What we really want to do is transform the object from its center instead. If you are a Club Greensock member then you could just use the transformAroundCenter plugin to accomplish this with just one line of code and without having to make the calculations yourself, but for the rest of us we'll need a quick workaround.
  We calculate the new x position based on the new width and we calculate the new y position based on the new height. Then we tween the
  x,
  y,
  width, and
  height properties to their new values. We also fade in the
  removeBtn and make the tag fully opaque.
  We do the complete opposite in the
  outState method which is called everytime the mouse hovers off of the tag. The tag is tweened back to its original state.
  The
  resize method accomplishes what the
  overState method accomplishes without affecting the
  alpha property and without any tweening. The
  resize method is called every time we want to resize the tag dynamically. The method takes one parameter which is the percentage to increase or decrease the tag's size by. The method adds a minimum size limit to the tag so that it does not become to small.
  The
  onMouseWheel method is called whenever a user interacts with the wheel on their mouse. The
  onKeyDownE method is called everytime a key is pressed. Each method only executes code if the tag is currently in edit mode. And each method resizes the tag based on specific properties. The
  onMouseWheel method resizes the tag based on the
  MouseEvent's
  delta property's value. The
  onKeyDownE increases the tag's size when the Up key is pressed and decreases the tags size when the Down key is pressed.
  Their is one last thing we need to fix in order to make our tag animate correctly. TweenLite changes the value of the
  width and
  height properties on each frame until the animation is complete. When you resize objects in Flash, the can become distorted. We don't want our tags looking distorted. To fix this problem we'll need to override the
  set width and
  set height methods from the parent class.
  public override function set width( value:Number ):void { draw( value, height ); } public override function set height( value:Number ):void { draw( width, value ); }
  Whenever the width or height of the tag is set, we want to redraw the tag's graphics. Create the
  draw method.
  private function draw( newWidth:Number, newHeight:Number ):void { graphics.clear(); graphics.lineStyle( LINE_THICKNESS, LINE_COLOR ); graphics.beginFill( FILL_COLOR, .5 ); graphics.drawRoundRect( 0, 0, newWidth, newHeight, ELLIPSE_WIDTH, ELLIPSE_HEIGHT ); }
  The
  draw method should accept two parameters: the new width of the tag and the new height of the tag. The graphics are cleared then redrawn again based on the
  newWidth and
  newHeight parameters. Now our tag will animate beautifully.
  Step 14: Entering and Exiting Edit Mode
  We want our users to be able to edit each tag individually. When a tag is in edit mode, the user can manipulate the tag's size and reposition the tag on the image. Several things need be done to accomplish this.
  First, let's create the
  enterEditMode and
  exitEditMode methods. Both of these methods will be public methods as we will need to call them from the document class.
  public function enterEditMode():void { if ( !_editMode ) { _editMode = true; removeEventListener( MouseEvent.ROLL_OUT, outState ); draw( _rectangle.width, _rectangle.height ); } } public function exitEditMode():void { if ( _editMode && !removed ) { _editMode = false; image.addChild( this ); x = _rectangle.x; y = _rectangle.y; stopDrag(); alpha = INIT_ALPHA; TweenLite.to( removeBtn, .1, { alpha:0 } ); addEventListener( MouseEvent.ROLL_OVER, overState ); } }
  The
  enterEditMode method executes the block of code within the
  if statement if the tag is currently not in edit mode. If the tag is not in edit mode the tag will enter edit mode, setting
  _editMode to
  true to allow the user to change the tag's properties. The
  ROLL_OUT event listener is removed as we don't wan't the method to accidently execute if the mouse hovers off of the tag. Finally, the
  draw method is called to display the original size of the tag.
  The
  exitEditMode method sets the tag back to its initial state while positioning the tag at the
  _rectangle's new x and y position. We call the
  stopDrag method just in case the tag was being dragged by the user when edit mode has been exited.
  Step 15: Creating a New Tag
  Now let's go back to our
  Document class,
  FaceTagger. Finally we can create the
  newTag method now that we have a
  PhotoTag class. Create the
  newTag method.
  private function newTag( rectangle:Rectangle ):void { var tag:PhotoTag = new PhotoTag( rectangle, image ); image.addChild( tag ); tag.addEventListener( MouseEvent.ROLL_OVER, onTagRollOver ); tag.addEventListener( MouseEvent.DOUBLE_CLICK, enterEditMode ); tag.addEventListener( Event.REMOVED, onTagRemoved ); }
  The method creates a new
  PhotoTag object passing the
  rectangle parameter and the current image into the
  PhotoTag contructor method. The tag is added to the current image. We listen for several events that the tag will dispatch. The first event is the
  ROLL_OVER event. A method called
  onTagRollOver is called when the event is dispatched. We listen for the
  DOUBLE_CLICK event so that we can call the
  enterEditMode method, which will be different from the
  enterEditMode method from the
  PhotoTag class, and finally we listen for the
  REMOVED event that calls the
  onTagRemoved method whenever the tag is removed from its parent object.
  Create an event handler method named
  onTagRollOver.
  private function onTagRollOver( e:MouseEvent ):void { if ( !e.target.editMode ) statusTxt.text = "double-click to edit"; }
  The method is very simple, as you can see. The method displays a message to the user if the tag that the mouse is hovering over is not in edit mode. The message notifies the user that if the double-clicks on the current tag, then the tag will enter edit mode.
  Step 16: Granting the User Access to Edit
  We now need to allow the user access to edit each tag. Create a new variable underneath the class delclaration of the
  FaceTagger class and name it
  currentTag. It should be a
  PhotoTag object. The beginning of the document class should now look like so:; private var currentTag:PhotoTag; public static const MIN_WIDTH:Number = 50; public static const MIN_HEIGHT:Number = 50; public static const MAX_WIDTH:Number = 1000; public static const MAX_HEIGHT:Number = 1000; public static const FILE_TYPES:String = "*.jpg; *.jpeg; *.bmp; *.png"; public function FaceTagger() {
  Create the
  enterEditMode method within the
  FaceTagger class. This method is the event handler method that we called upon in the
  newTag method.
  private function enterEditMode( e:MouseEvent ):void { statusTxt.text = "click the background to exit 'edit' mode\n"; statusTxt.appendText( "use the mouse wheel or the up and down\n" ); statusTxt.appendText( "arrow keys to resize the tag" ); var tag:PhotoTag = e.target as PhotoTag; darkBox.visible = true; addChild( darkBox ); addChild( tag ); addChild( statusTxt ); tag.x = image.x + tag.rectangle.x; tag.y = image.y + tag.rectangle.y; tag.enterEditMode(); currentTag = tag; positionContents(); }
  The method above notifies the user that they are currently in edit mode. The screen is darkened and the tag is removed from the
  image object and placed on the
  stage. The tag's
  x and
  y properties have to be set to values that are relevant to the image's position on the stage. If we didn't do this the tag would just sit in the top left hand corner of the screen. When this method is called, it won't even seem as if the tags position has changed at all but in reality it has changed quite a bit.
  Finally we call the
  tag objects's
  enterEditMode method, assign a reference to the
  tag object to the
  currentTag variable and position the contents of the screen (particularly the
  statusTxt textfield).
  Step 17: Saving the State of the Current Tag
  After the user has finished editing the
  currentTag, the tag needs to be added back to the
  image object and correctly positioned. Create the
  exitEditMode method within the
  FaceTagger class.
  private function exitEditMode( e:MouseEvent = null ):void { darkBox.visible = false; if ( currentTag ) { statusTxt.text = " "; currentTag.rectangle.x = currentTag.x - image.x; currentTag.rectangle.y = currentTag.y - image.y; currentTag.exitEditMode(); currentTag = null; positionContents(); } }
  Notice how the
  MouseEvent parameter is set to
  null by default. We are going to call this method from the
  onTagRemoved event handler method later and we won't have a
  MouseEvent object to pass as the method's parameter so we give the parameter a
  null default value. This makes the method more accessible.
  The first task the method performs is hiding the
  darkBox object to give the user a sense of exiting edit mode. The block of code within the
  if statement executes if the
  currentTag exists. The textfield is set to a single space (
  " "). Remember that the textfield has its
  autoSize property set to resize from its center. To get the textfield to position itself correctly, we need to make sure that there is some kind of text present so that the textfield doesn't resize itself down to nothing. This can cause a potential problem if the user exits edit mode then hovers over a tag. The effect caused is that the textfield may appear off screen.
  Next, the
  currentTag's
  rectangle object is given new
  x and
  y property values. These values are based on the tag's current position on the
  stage relative to the
  image's position on the
  stage. When the
  currentTag's
  exitEditMode method is called the
  currentTag is added back to the
  image object and positioned to the
  rectangle's new
  x and
  y position.
  Last, we set the reference of the
  currentTag to
  null and position the contents on the screen.
  Create the
  onTagRemoved method.
  private function onTagRemoved( e:Event ):void { if ( e.target.removed ) { exitEditMode(); } }
  This method exits edit mode if the
  remove method of the targeted tag (
  e.target) has been called. Thus if the user has clicked the remove button on the targeted tag, we exit editMode. Without this method, if the user removed a tag while in edit mode, the screen would remain dark.
  Step 18: Repositioning a Tag
  Return to the
  PhotoTag class and add the following methods to the class.
  private function onMouseDown( e:MouseEvent ):void { if ( !_editMode ) return; removeEventListener( MouseEvent.MOUSE_DOWN, onMouseDown ); var thisRect:Rectangle = image.getRect( this ); startDrag( false, new Rectangle( image.x, image.y, thisRect.width - _rectangle.width, thisRect.height - _rectangle.height ) ); addEventListener( MouseEvent.MOUSE_UP, onMouseUp ); } private function onMouseUp( e:MouseEvent ):void { if ( !_editMode ) return; removeEventListener( MouseEvent.MOUSE_UP, onMouseUp ); stopDrag(); addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown ); }
  Both methods require that the tag be in edit mode to execute completely. The
  onMouseUp method starts dragging the tag and limits the tag to only drag within the
  _image object. The
  onMouseUp method stops the dragging process.
  Step 19: Adding Additional Tags
  By now you're probably wondering what happened to
  addBtn. When this button is clicked a new
  PhotoTag object is added to the current image. Let's create the
  addTag method in the document class.
  Note: You should remember this method from Step 6. It is the method that was passed as the eventhandler parameter when we added an event listener that listens for a
  CLICK event to be dispatched from the
  addBtn object.
  private function addTag( e:MouseEvent ):void { if ( image ) { var rect:Rectangle = new Rectangle( 0, 0, 75, 75 ); newTag( rect ); } }
  If
  image exists, we call the
  newTag method as before. We create a new made up
  Rectangle object so that the user can customize the tag on their own. The tag is simply added to the image in the top left corner.
  Step 20: Improving the Appearence of the RemoveButton Object
  As we have seen, you can dramatically improve an object's appearance with a few lines of code. Let's improve the look of the
  RemoveButton object. Create a new class and name it
  RemoveButton. The class will have to extend the
  MovieClip class since it is linked to a library symbol of that type.
  Save the class to the root folder. Import the following within
  RemoveButton:
  import flash.display.MovieClip; import flash.filters.DropShadowFilter; import flash.filters.BevelFilter;
  All we're going to do now is add a simple line of code within the
  RemoveButton object's class constructor method.
  filters = [ new DropShadowFilter( 5, 45, 0, 1, 5, 5, 1, 3 ), new BevelFilter( 10, 90, 0xF5E1AF, .6, 0, 1, 15, 15, 1, 3 ) ];
  We have just added a
  DropShadowFilter and a
  BevelFilter to the
  RemoveButton object. This will add a great deal of depth to our button.
  Step 21: Testing Our Application
  At this point, if we test our application, everything should run smoothly. But we will encounter a problem when we upload an image and the face detection process begins. If you do not put the face.zip file in the same directory as the SWF, the face detection process can not occur. It is very important to remember to do this. Once you have placed face.zip into the same directory as the SWF, you may then run the application.
  Conclusion
  Please take into consideration that the Face Recognition Library isn't perfect. There will be times where it won't detect any faces even though there are faces within the image that was uploaded. There will also be times where only some faces in an image are detected and times where patterns that look like faces (e.g., A cloud shaped like a face) will be detected as faces. This is why we allow for our users to edit tags. Generally, I found the library pretty amazing and I hope you will too. This concludes my tutorial. Thank you for reading.
  Envato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!Translate this post
  