Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Quick Tip: Creating a Snapshot Tool in Flash

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

In this Quick Tip, I'll show you how to create a Shapshot Tool that copies part of the stage and saves the result as a PNG image.


Final Result Preview

This is the final result. Just click the stage and then drag the mouse to take a snapshot.


Step 1: Download the as3corelib Class

Create a new folder for this project and give it any name you want. Go to Github and download the latest version of the as3corelib Class. For this Quick Tip I've used version .93. Extract the ZIP file and go to as3corelib-.93 > src.

Copy the com directory to your newly created folder. This package has a very useful PNGEncoder Class that we will use for encoding the
snapshot into a PNG image.


Step 2: Setup your Flash File

Launch Flash and create a new Flash Document. Make sure it's set to publish to Actionscript 3.0 and Flash Player 10. You can check this in the Properties
panel or by selecting Publish Settings... and then clicking on the Flash tab.

The Flash Properties Panel

Step 3: Content to be Snapped

We need some content in the Flash file to check if the snapshot tool is working properly. We're going to create some circles and place them randomly around the stage. Create a new Document Class called Circles.as and add the following code. Remember to link the Class to the Flash file by writing Circles in the Class field in the the Properties Panel.

package  
{
	import flash.display.Shape;
	import flash.display.Sprite;
	
	public class Circles extends Sprite
	{
		private var _circleCount:int = 20;
		
		public function Circles() 
		{
			makeCircles();
		}
		
		private function makeCircles():void
		{
			for (var i:int = 0; i < _circleCount; i++) 
			{
				var circle:Shape = new Shape();
				circle.graphics.lineStyle(1, 0xCCCCCC, 1);
				circle.graphics.beginFill(0x333333, 0.5);
				circle.graphics.drawCircle(Math.random() * stage.stageWidth, Math.random() * stage.stageHeight, (Math.random() * 40) + 20);
				circle.graphics.endFill();
				addChild(circle);
			}
		}
	}
}

Our snapshot function will work with any stage contents, though, so don't feel that you have to restrict yourself to simple shapes!


Step 4: Create the SnapShot Class

Create a new Class file and give it a name of SnapShot.as. This is the Class that will hold all the methods used to take a snapshot. Add the following code to the Class.

package
{
	import flash.display.Stage;
	
	public class SnapShot
	{
		private var _stage:Stage;
		
		public function Snapshot() {}
		
		public function activate(stage:Stage):void
		{
			_stage = stage;
		}
	}
}

Add the following lines of code to the Circles Class. We use the activate() method to pass a reference to the Stage along to the SnapShot Class. We do this to so we can access the content on the Stage.

package
{
	import flash.display.Shape;
	import flash.display.Sprite;
	
	public class Circles extends Sprite
	{
		private var _circleCount:int = 20;
		private var _snapshot:SnapShot;
		
		public function Circles() 
		{
			makeCircles();
			_snapshot = new SnapShot();
			_snapshot.activate(stage);
		}
		
		private function makeCircles():void
		{
			for (var i:int = 0; i < _circleCount; i++) 
			{
				var circle:Shape = new Shape();
				circle.graphics.lineStyle(1, 0xCCCCCC, 1);
				circle.graphics.beginFill(0x333333, 0.5);
				circle.graphics.drawCircle(Math.random() * stage.stageWidth, Math.random() * stage.stageHeight, (Math.random() * 40) + 20);
				circle.graphics.endFill();
				addChild(circle);
			}
		}
	}
}

Step 5: Drawing the Boundaries

Expand the SnapShot Class to include the following methods. These methods are used to draw the boundaries frame, which allows users to select which part of the stage will be copied to the snapshot.

package  
{
	import flash.display.Shape;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	public class SnapShot
	{
		private var _stage:Stage;
		private var _boundary:Shape;
		private var _originX:int;
		private var _originY:int;
		private var _mouseX:int;
		private var _mouseY:int;
		
		public function SnapShot() {}
		
		public function activate(stage:Stage):void
		{
			_stage = stage;
			addMouseListeners();
		}
		
		private function addMouseListeners():void
		{
			_stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			_stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		}
		
		private function onMouseDown(e:MouseEvent):void 
		{
			_stage.addEventListener(MouseEvent.MOUSE_MOVE, drawBoundaries);
			
			//These values are used later as a starting point for the boundary.
			_originX = _stage.mouseX;
			_originY = _stage.mouseY;
		}
		
		private function drawBoundaries(e:MouseEvent):void 
		{
			if (_boundary == null) { _boundary = new Shape(); } 
			
			clearBoundaries()
			
			//This is to make the mouseY value stay within the limits of the Stage.
			_mouseY = Math.max(Math.min(_stage.mouseY,_stage.stageHeight), 0);
			//This is to make the mouseX value stay within the limits of the Stage.
			_mouseX = Math.max(Math.min(_stage.mouseX,_stage.stageWidth), 0);
			
			_boundary.graphics.lineStyle(2, 0x0, 0.5);
			_boundary.graphics.drawRect(_originX, _originY, _mouseX - _originX, _mouseY - _originY);
			_boundary.graphics.lineStyle(4, 0x0, 0.2);
			//This code makes sure we always draw from the top left point to the bottom right.
			_boundary.graphics.drawRect(Math.min(_originX, _mouseX) - 3, Math.min(_originY, _mouseY) - 3, Math.abs(_mouseX - _originX) + 6, Math.abs(_mouseY - _originY) + 6);
			_stage.addChild(_boundary);
		}
		
		private function clearBoundaries():void
		{
			_boundary.graphics.clear();
		}
		
		private function onMouseUp(e:Event):void 
		{
			_stage.removeEventListener(MouseEvent.MOUSE_MOVE, drawBoundaries);
			clearBoundaries();
		}
	}
}

We start by checking if the user has clicked on the Stage. When he clicks on the stage we start running the drawBoundaries() method whenever the mouse is moved. This method draws the boundaries; whatever falls within the thin black line will be part of the snapshot. When the user releases the mouse we stop checking for mouse movements.

Step 6: Stage Content to Bitmap

Import the BitmapData and Matrix Classes and add the _content property to the list of private properties.

package  
{
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	
	public class SnapShot
	{
		private var _stage:Stage;
		private var _boundary:Shape;
		private var _content:BitmapData;
		private var _originX:int;
		private var _originY:int;
		private var _mouseX:int;
		private var _mouseY:int;

Add the following code to the bottom of the Class:

private function onMouseUp(e:Event):void 
{
	_stage.removeEventListener(MouseEvent.MOUSE_MOVE, drawBoundaries);
	clearBoundaries();
	createBitmap();
}
		
private function createBitmap():void
{
	//We add the -2 to offset for the boundary line.
	_content = new BitmapData(Math.abs(_mouseX - _originX) - 2, Math.abs(_mouseY - _originY) - 2);
	//The -1 is added for the same reason, to keep the line from appearing in the final image.
	var bitmapMatrix:Matrix = new Matrix(1, 0, 0, 1, -Math.min(_originX, _mouseX) - 1, -Math.min(_originY, _mouseY) - 1);
	_content.draw(_stage, bitmapMatrix);
}

The createBitmap() method creates a new BitmapData object with the width and the height of the content area inside the boundary. The matrix variable transitions (moves) the image so that when the draw() method is called it starts copying from the top left corner of the boundary area.

Step 7: Saving the Bitmap

To save the bitmap we need to import several Classes.

  • The ByteArray Class is used to encode the BitmapData object.
  • The PNGEncoder Class is used to convert the encoded data into a PNG Image.
  • The FileReference Class is used to save the image to the users hard drive.

We've also added an _imageCount property which we use to increment the image names.

package  
{
	import com.adobe.images.PNGEncoder;
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.net.FileReference;
	import flash.utils.ByteArray;
	
	public class Snapshot
	{
		private var _stage:Stage;
		private var _boundary:Shape;
		private var _content:BitmapData;
		private var _originX:int;
		private var _originY:int;
		private var _mouseX:int;
		private var _mouseY:int;

		private var _imageCount:int = 1;

Add the following code to the bottom of the SnapShot Class:

private function createBitmap():void
{
	_content = new BitmapData(Math.abs(_mouseX - _originX) - 2, Math.abs(_mouseY - _originY) - 2);
	var bitmapMatrix:Matrix = new Matrix(1, 0, 0, 1, -Math.min(_originX, _mouseX) - 1, -Math.min(_originY, _mouseY) - 1);
	_content.draw(_stage, bitmapMatrix);
			
	saveBitmap();
}
		
private function saveBitmap():void
{
	var encodedContent:ByteArray = PNGEncoder.encode(_content);
	var fileWindow:FileReference = new FileReference();
	fileWindow.save(encodedContent, "Image_" + _imageCount + ".png");
	_imageCount++;
}

The saveBitmap method is fairly easy to understand. We encode the BitmapData object and save it to the user's hard drive.
We use the _imageCount property to make it easier for user to save several images in a row.

Conclusion

The Snapshot Tool is now complete and with just three lines of code can be implemented into any project.

Make sure you're running Flash Player 10 and that you have the as3corelib package in the correct directory.

I hope you enjoyed this Quick Tip, thank you for reading!

Advertisement