In this Premium Tutorial, we'll learn how to manipulate Bitmaps in ActionScript 3 to produce a helpful image cropping application. Keep reading!
Final Result Preview
Image by Swami Stream licenced under Creative Commons.
Step 1: Overview
Using the Flash Tools we'll create an attractive interface that will be powered by several ActionScript 3 classes like MouseCursor, Bitmap, BitmapData, Rectangle, Point, Tween, FileReference and even external libraries.
The user will be able to crop an image multiple times to later select the best option and save it to disk.
Step 2: Set Up Flash
Open Flash and create a 600 pixels wide, 400 pixels tall document. Set the Frame rate to 24fps.

Step 3: Interface

A nice looking mac-like interface will power our code, this involves multiple timeline based buttons, custom cursors and more.
Continue to the next steps to learn how to create this GUI.
Step 4: Background

No science in the background, just create a 600x400px black rectangle and center it in the stage. You can also change the background color in the Stage Properties.
Step 5: Image
We will need an image to crop, select your prefered image and import it to the stage (Cmd + R).
Image by Swami Stream licenced under Creative Commons.
Step 6: Custom Cursor
We'll make a custom cursor to use it as feedback to the user, letting him know where he can crop.
Select the Rectangle Tool (R) and make a 3px wide, 17px tall white rectangle.

Duplicate the shape (Cmd+D) and rotate it 90 degrees to form a cross.

Repeat this process with a 1px wide, 15 px tall black rectangle.

Convert the final shape to MovieClip (F8) and set its instance name to cursor.
Step 7: Action Buttons
These buttons handle secondary actions based in the crop, these actions are:
- Save: Saves the current crop.
- Cancel: Returns the current crop to its position and brings back the original image.
- Clear: Erases all the crops and brings back the original image.
Select the Rectangle Primitive Tool (R) and change the corner radius to 10, draw a 70x18px rectangle and fill it with #666666.

Duplicate the shape (Cmd + D), resize it to 68x16px and change its color to this linear gradient #222222 to #444444. Use the Gradient Transform Tool (F) to rotate the gradient.

Next, use the Text Tool (T) to write a label for the button. Use this format: Lucida Grande Regular, 12pt, #CCCCCC.

Use the same technique to create the Cancel and Clear buttons.

Step 8: Buttons Timeline
A well made GUI button has 4 states:
- Up: The normal state of the button.
- Over: The graphics shown when the Mouse Cursor is over the button.
- Down: Shown when the Mouse is clicking the button.
- Hit: The area where the mouse can click.
Convert your buttons to MovieClip and double click them to enter edit mode. Open the Timeline Panel (Window > Timeline).
You'll notice that the Up state is already created, these are the shapes you converted to MovieClip.

Press F6 to create a new Frame and change the center shape gradient fill to #222222, #5B5B5B. This will be the Over state.

For the Down state, select the center shape and flip it vertically (Modify > Tranform > Flip Vertical).

The Hit state is by default, the bigger shape area, as the clickable area we want is the whole button, there will be no need to create a frame for this.
Step 9: Position and Instance Names
When all your buttons are ready, exit edit mode and place them as shown in the following screenshot. The white text indicates the button instance name.

Step 10: Button Bar
A button bar will be used to place and highlight the crop button.
Use the Rectangle Tool to create a 600x50 px rectangle and fill it this gradient fill #AFAFAF to #C4C4C4. Align the bar in the bottom of the stage.

To create a embossed effect, draw two 600x1px lines and place them above the button bar, fill the top one with #858585 and the other with #D8D8D8.

Step 11: Crop Button
The Crop button will start the Main ActionScript function that will manipulate the bitmaps in the stage.
With the Rectangle Tool, create a 33x6px and a 26x6px rectangles and use them to form a right angle.

Duplicate the shape and rotate it 180 degrees to form a square.

Move the duplicated shape 5px up and 5px to the right.

Fill the resulting shape with this gradient fill: #444444 to #222222. Use the Gradient Transform Tool to rotate the fill.

You can add more detail by adding a shadow; duplicate the current shape and move it 1px down and 1px right.

Lastly, convert the shape to MovieClip and name it cropButton.
Step 12: Crop Shape

The crop shape is an image that will be used to indicate the area that will be cropped.
Select the Rectangle Tool and change the stroke color to white and the fill color to white with 1% alpha (this will help us drag the crop shape). Draw a 10x10px square and center it.

Select a 1px part of the square and change its color to black.

Duplicate the shape and do the same on all the side.

Repeat this process on all the sides.

Convert the result to MovieClip and name it cropShape, mark the Export for ActionScript box.
Double click it to enter edit mode, create a new Keyframe in frame 5 and rotate the shape 180 degrees.

Add 4 frames more and exit edit mode.
This ends the graphic part, let's start with ActionScript!
Step 13: New ActionScript Class
Create a new (Cmd + N) ActionScript 3.0 Class and save it as Main.as in your class folder.

Step 14: Package
The package keyword allows you to organize your code into groups that can be imported by other scripts, it's recommended to name them starting with a lowercase letter and use intercaps for subsequent words for example: myClasses. It's also common to name them using your company's website: com.mycompany.classesType.myClass.
In this example, we're using a single class, so there isn't really a need to create a classes folder.
package {
Step 15: Import Directive
These are the classes we'll need to import for our class to work, the import directive makes externally defined classes and packages available to your code.
import flash.display.Sprite; import flash.events.MouseEvent; import flash.ui.Mouse; import flash.ui.MouseCursor; import flash.display.BitmapData; import flash.display.Bitmap; import flash.geom.Rectangle; import flash.geom.Point; import fl.transitions.Tween; import fl.transitions.easing.Strong; import flash.net.FileReference; import flash.utils.ByteArray; import com.adobe.images.JPGEncoder; import flash.events.Event;
Step 16: JPGEncoder

In order to save the image crop, we'll use a class which is part of the as3corelib. Follow the link and download the library.
Step 17: Declaring and Extending
Here we declare the class using the class definition keyword followed by the name that we want for the class, remember that you have to save the file using this name.
The extends keyword defines a class that is a subclass of another class. The subclass inherits all the methods, properties and functions, that way we can use them in our class.
public class Main extends Sprite {
Step 18: Variables
These are the variables we'll use, read the comments in the code to find out more about them.
private var cropShape:CropShape; //This is an instance of the cropShape we created before private var pointX:Number; //This var will hold the x position where the crop shape is started private var pointY:Number; //This var will hold the y position where the crop shape is started private var added:Boolean; //Checks if the crop shape is in stage private var images:Array = new Array(); //Stores the images crops private var bmd:BitmapData; //A bitmap data object, used to manipulate the main image data private var bmd2:BitmapData; //A second bitmap data object, this one will hold the data of the image we want to save private var croppedImage:Sprite; //Holds the cropped images private var cropThumb:int = 0; //The number of thumbs already created private var thumbPosX:Array = [5, 5, 5, 505, 505, 505]; //Stores the x positions of the thumbs private var thumbPosY:Array = [37, 135, 233, 37, 135, 233]; //Stores the y positions of the thumbs private var tween:Tween; //A tween object, the default animation library in flash private var fileReference:FileReference; //Used to save the file to disk private var byteArray:ByteArray; //Stores binary data, used to save the file to disk private var jpg:JPGEncoder = new JPGEncoder(); //The image encoder private var zoomed:Boolean; //Checks if the thumbnail is zoomed in or out private var currentCrop:Bitmap; //Holds the current zoomed thumbnail, the one that will be saved private var currentSprite:*; //Used to know what thumb is active private var latestX:Number; //Checks the latest x of the zoomed thumb private var latestY:Number; //Checks the latest y of the zoomed thumb
Step 19: Constructor
The constructor is a function that runs when an object is created from a class, this code is the first to execute when you make an instance of an object or runs using the Document Class.
public function Main():void {
Step 20: Initial Listeners
These are the listeners that will be defined at launch, they basically add Mouse related events to buttons.
image.addEventListener(MouseEvent.MOUSE_DOWN, getStartPoint); image.addEventListener(MouseEvent.MOUSE_UP, stopDrawing); cropButton.addEventListener(MouseEvent.MOUSE_UP, crop); image.addEventListener(MouseEvent.MOUSE_OVER, customCursor); image.addEventListener(MouseEvent.MOUSE_OUT, removeCustomCursor); saveButton.addEventListener(MouseEvent.MOUSE_UP, saveImage); cancelButton.addEventListener(MouseEvent.MOUSE_UP, cancel); clearButton.addEventListener(MouseEvent.MOUSE_UP, clearThumbs);
Step 21: Hide Buttons
This code hides the buttons that aren't in use at the moment.
saveButton.visible = false; cancelButton.visible = false; clearButton.visible = false; cursor.visible = false;
Step 22: Add Custom Cursor
The following function makes the custom cursor visible when the mouse pointer is over the main image.
private function customCursor(e:MouseEvent):void { cursor.visible = true; Mouse.hide(); cursor.startDrag(true); }
Step 23: Remove Custom Cursor
Hides the custom cursor when the mouse pointer leaves the main image.
private function removeCustomCursor(e:MouseEvent):void { cursor.visible = false; Mouse.show(); cursor.stopDrag(); }
Step 24: Get Start Point
A very important function, gets and stores the mouse click coordinates and places the cropShape movieclip in them, the current value will be used later to determine the size of the crop shape.
private function getStartPoint(e:MouseEvent):void { pointX = mouseX; pointY = mouseY; if (! added) { cropShape = new CropShape(); cropShape.x = pointX; cropShape.y = pointY; addChild(cropShape); added = true; } else { removeChild(cropShape); cropShape = new CropShape(); cropShape.x = pointX; cropShape.y = pointY; addChild(cropShape); }
Step 25: Crop Mouse Listeners
Adds a listener in the main image to expand the crop shape on mouse movement and adds the listener to stop expanding on mouse up.
image.addEventListener(MouseEvent.MOUSE_MOVE, drawCropShape); cropShape.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);
Step 26: Draw Crop Shape
Expands the cropShape according to the saved coordinates and the current ones.
private function drawCropShape(e:MouseEvent):void { cropShape.width = mouseX - pointX; cropShape.height = mouseY - pointY; }
Step 27: Stop Crop Shape
Stops the crop shape expansion and adds some listeners that will be used by the next functions.
private function stopDrawing(e:MouseEvent):void { image.removeEventListener(MouseEvent.MOUSE_MOVE, drawCropShape); cropShape.addEventListener(MouseEvent.MOUSE_OVER, showHandCursor); cropShape.addEventListener(MouseEvent.MOUSE_OUT, hideHandCursor); cropShape.addEventListener(MouseEvent.MOUSE_DOWN, dragCrop); cropShape.addEventListener(MouseEvent.MOUSE_UP, stopDragCrop); }
Step 28: Show Hand Cursor
Uses the Mouse class to manipulate the mouse cursor, this code will show the Hand cursor when the mouse is over the crop shape.
private function showHandCursor(e:MouseEvent):void { Mouse.cursor = MouseCursor.HAND; }
Step 29: Hide Hand Cursor
Restores mouse cursor original behaviour.
private function hideHandCursor(e:MouseEvent):void { Mouse.cursor = MouseCursor.AUTO; }
Step 30: Drag Crop
The crop shape will be draggable, this will help select the area we want easily.
private function dragCrop(e:MouseEvent):void { cropShape.startDrag(); }
Step 31: Stop Drag Crop
Stops the drag on mouse up.
private function stopDragCrop(e:MouseEvent):void { cropShape.stopDrag(); }
Step 32: Crop Function
This function will handle the image cropping, using the images bitmap data and the sprite class to create a series of thumbnails that will be elegible to save.
private function crop(e:MouseEvent):void {
Step 33: Bitmap Data
The next lines handle the bitmap data required to crop the image.
bmd = new BitmapData(image.width,image.height,false,0x00000000); //Creates a new bitmap data object using the size of the main image bmd.draw(image); //Copies the main image data to the instance bmd2 = new BitmapData(cropShape.width,cropShape.height,false,0x00000000); //Creates a new bitmap data using the actual size of the crop shape
Step 34: Copy Image Pixels
The next line copies the pixels of the main Image situated in the crop shape position to the bitmap data object bmp2.
The parameters work as listed below:
- bmd: The source bitmap data to copy from, the main image
- Rectangle: Specifies the position of the pixels to copy, the crop shape position
- Point: Specifies the point to start copying, from the point 0 of the rectangle
bmd2.copyPixels(bmd, new Rectangle(cropShape.x - image.x, cropShape.y - image.y, cropShape.width, cropShape.height), new Point(0, 0));
Step 35: Create Thumbnail
We are going to let the user crop six times and save those previews at the side of the main image, for that, we create a new bitmap that will store the bitmap data of the cropped thumbnail and then we add it as a 90x70px sprite.
We also add a listener to zoom in and out the thumbnail.
if(cropThumb < 6) { var bmp:Bitmap = new Bitmap(bmd2); var thumb:Sprite = new Sprite(); thumb.addChild(bmp); thumb.width = 90; thumb.height = 70; thumb.addEventListener(MouseEvent.MOUSE_UP, zoomThumb); addChild(thumb);
Step 36: Access Thumbnail
As we create a new sprite in every crop, the last sprite will be inaccesible using its instance name, time to use the array we created before.
This array will store the created thumbnails to access them outside the function.
images.push(thumb);
Step 37: Tween Thumbnails
When the user presses the crop button a thumbnail is created using the cropped image, this thumbnail is later animated to the sides of the application depending on a variable.
The thumbnail position is determined by this variable and the thumbPos arrays.
tween = new Tween(thumb, "x", Strong.easeOut, cropShape.x, thumbPosX[cropThumb], 0.5, true); tween = new Tween(thumb, "y", Strong.easeOut, cropShape.y, thumbPosY[cropThumb], 0.5, true); cropThumb++; // Adds one to the number of thumbs
Step 38: Save Image
The next function is used to save the image to disk.
First, it uses the jpg.encode() method and saves the resulting data to the byte array, then the fileReference object is used to display a save dialog where the user can rename the file created (although a default name is set).
private function saveImage(e:MouseEvent):void { fileReference = new FileReference(); byteArray = jpg.encode(currentCrop.bitmapData); fileReference.save(byteArray, "Crop.jpg"); fileReference.addEventListener(Event.COMPLETE, saveComplete); }
Step 39: Save Complete
Once the image is saved, the thumbnails are removed from the stage and from the array. The buttons are hidden and the main image returns.
private function saveComplete(e:Event):void { for(var i:int = 0; i < images.length; i++) { removeChild(images[i]); } cropThumb = 0; images = []; tween = new Tween(image,"y",Strong.easeOut,image.y,stage.stageHeight / 2 - image.height / 2 - 30,0.5,true); added = false; saveButton.visible = false; cancelButton.visible = false; clearButton.visible = false; }
Step 40: Cancel
There is also a cancel button that will let you browse through the thumbnails without saving any of them.
When this button is pressed it returns all the thumbnails to postition and brings back the main image to crop more (if possible).
private function cancel(e:MouseEvent):void { tween = new Tween(currentSprite,"width",Strong.easeOut,currentSprite.width,90,0.5,true); tween = new Tween(currentSprite,"height",Strong.easeOut,currentSprite.height,70,0.5,true); tween = new Tween(currentSprite,"x",Strong.easeOut,currentSprite.x,latestX,0.5,true); tween = new Tween(currentSprite,"y",Strong.easeOut,currentSprite.y,latestY,0.5,true); tween = new Tween(image,"y",Strong.easeOut,image.y,stage.stageHeight / 2 - image.height / 2 - 30,0.5,true); added = false; saveButton.visible = false; cancelButton.visible = false; clearButton.visible = false; cropButton.visible = true; zoomed = false; }
Step 41: Clear Thumbnails
If the user has cropped the 6 times allowed by the app, and none of them is the expected result, there's always a way to crop even more times. This is the task that the clear button will achieve.
It removes all thumbnails from the stage and from the array, returns the main image to stage and hides the unused buttons.
private function clearThumbs(e:MouseEvent):void { for(var i:int = 0; i < images.length; i++) { removeChild(images[i]); } cropThumb = 0; images = []; tween = new Tween(image,"y",Strong.easeOut,image.y,stage.stageHeight / 2 - image.height / 2 - 30,0.5,true); added = false; saveButton.visible = false; cancelButton.visible = false; clearButton.visible = false; }
Step 42: Document Class

We'll make use of the Document Class in this tutorial, if you don't know how to use it or are a bit confused please read this QuickTip.
Conclusion
The final result is a helpful Image Cropping application that teaches you how to manipulate bitmaps to modify them, and almost without knowing it, you also learned how to create and implement a very nice interface.
I hope you liked this tutorial, thank you for reading!
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post