One By One Design

Saving Files Directly from Flash Player 10

So, while surfing around checking out the new Flash 10 features I ran across this intriguing quote over at

File Reference runtime access — Bring users into the experience by letting them load files into your RIA. You can work with the content at runtime and even save it back when you are done through the browse dialog box. Files can be accessed as a byteArray or text using a convenient API in ActionScript without round-tripping to the server. You no longer have to know a server language or have access to a server to load or save files at runtime.

Needless to say, I had to investigate this further. Sho ’nuff, if you check out the documentation for the FileReference object you’ll see a new save() method which accepts all manner of objects for its first argument (the second argument is just a string for the default file name). It so happens, if the first object is a ByteArray, it will simply write the instance, as is, straight to the users hard drive. Freaking amazing. What does this mean? Well, first off a lot less coding for the developer (no server side script to deal with). In addition, as the quote above points out, it means fewer trips to the server and fewer trips to the server means less bandwidth and less bandwidth means happier clients.

To give this a try I went back to my simple drawing application from a few posts ago and this time I enabled the “save” feature. Clicking the save button will turn your work of art into a ByteArray via the JPGEncoder class from the Adobe as3corelib package and the FileReference instance will deliver it straight to your desktop. No muss no fuss.

All this with only a simple little script like this:

package {  

	import com.adobe.images.JPGEncoder; 
	import com.onebyonedesign.drawing.DrawingTablet; 
	import com.onebyonedesign.ui.OBO_ValueSlider; 
	import flash.display.Sprite; 
	import flash.text.TextField; 
	import flash.text.TextFieldAutoSize; 
	import flash.text.TextFieldType; 
	import flash.text.TextFormat; 
	import flash.utils.ByteArray;  

	* Use FileReference instance to save image data directly from Flash to user's computer! 
	* @author Devon O. 

	[SWF(width="500", height="500", backgroundColor="#FFFFFF", framerate="31")] 
	public class SaveImage extends Sprite {  

		private var _fr:FileReference; 
		private var _imageBytes:ByteArray; 
		private var _fmt:TextFormat = new TextFormat("_sans", 11); 
		private var _titleText:TextField; 
		private var _qualityText:TextField; 
		private var _qualitySlider:OBO_ValueSlider;  

		public function SaveImage():void { 
			_fr = new FileReference();  

			var tablet:DrawingTablet = new DrawingTablet(400, 400, 0xF4EBB9); 
			tablet.x = 50; 
			tablet.addEventListener(DrawingEvent.SAVE, onSave); 

			// Some user input stuff to determine file name and quality  

			var titleLabel:TextField = new TextField(); 
			titleLabel.defaultTextFormat = _fmt; 
			titleLabel.selectable = false; 
			titleLabel.mouseEnabled = false; 
			titleLabel.autoSize = TextFieldAutoSize.LEFT; 
			titleLabel.x = 50; 
			titleLabel.y = 410; 
			titleLabel.text = "File Name:"; 

			_titleText = new TextField(); 
			_titleText.defaultTextFormat = _fmt; 
			_titleText.type = TextFieldType.INPUT; 
			_titleText.border = true; 
			_titleText.maxChars = 23; 
			_titleText.restrict = "A-Z_a-z0-9"; 
			_titleText.width = 150; 
			_titleText.height = 17; 
			_titleText.x = Math.round(titleLabel.textWidth + 55); 
			_titleText.y = 410; 

			var qualityLabel:TextField = new TextField(); 
			qualityLabel.defaultTextFormat = _fmt; 
			qualityLabel.selectable = false; 
			qualityLabel.mouseEnabled = false; 
			qualityLabel.autoSize = TextFieldAutoSize.LEFT; 
			qualityLabel.x = 270; 
			qualityLabel.y = 410; 
			qualityLabel.text = "Image Quality:"; 

			_qualitySlider = new OBO_ValueSlider(50, 1, 100, 50); 
			_qualitySlider.x = Math.round(qualityLabel.x + qualityLabel.textWidth + 10); 
			_qualitySlider.y = 416; 
			_qualitySlider.addEventListener(ValueSliderEvent.DRAG, qualityHandler); 

			_qualityText = new TextField(); 
			_qualityText.defaultTextFormat = _fmt; 
			_qualityText.border = true; 
			_qualityText.selectable = false; 
			_qualityText.mouseEnabled = false; 
			_qualityText.width = 40; 
			_qualityText.height = 17; 
			_qualityText.x = Math.round(_qualitySlider.x + _qualitySlider.width + 10); 
			_qualityText.y = 410; 
			_qualityText.text = "50"; 

		private function qualityHandler(event:ValueSliderEvent):void { 
			_qualityText.text = Math.round(event.value).toString(); 

		private function onSave(e:DrawingEvent):void { 
			var encoder:JPGEncoder = new JPGEncoder(Number(_qualityText.text)); 
			_imageBytes = encoder.encode(e.image);, (_titleText.text || "my_drawing") + ".jpg"); 

It’s just that easy. But don’t tell anyone. Make them think you work hard for your money.

You know, back when Adobe aquired Flash, I was very worried they would concentrate mainly on it’s design ability and let the development aspect fall by the wayside (you ever try writing expressions in After Effects? In a word, it sucks). I was 100% wrong about that though. The Flash platform (Flash, Flex, and AIR) have become mindbendingly impressive in both design and development sides. Thank you, Adobe. Thank you, Astro.

Of course, again, you’ll need the Flash 10 plugin to view the example below:

[kml_flashembed movie=”” height=”500″ width=”500″ /]

Oh, and here’s a quickie bonus 3d cube example – script only, you’ll have to compile yourself:

package {  

	import flash.display.Sprite; 

	[SWF(width="500", height="400", backgroundColor="#FFFFFF", framerate="31")] 
	public class CubeExample extends Sprite {  

		private static const CUBE_SIZE:int = 150;  

		private var cube:Sprite;  

		public function CubeExample():void { 
			addEventListener(Event.ENTER_FRAME, frameHandler); 

		private function initCube():void { 
			cube = new Sprite();  

			var s1:Sprite = createSide(); 
			var s2:Sprite = createSide(); 
			var s3:Sprite = createSide(); 
			var s4:Sprite = createSide(); 
			var s5:Sprite = createSide(); 
			var s6:Sprite = createSide();  

			s1.z = CUBE_SIZE * .5; 
			s2.z = -CUBE_SIZE * .5; 
			s3.rotationY = 90; 
			s3.x = CUBE_SIZE * .5; 
			s4.rotationY = 90; 
			s4.x = -CUBE_SIZE * .5; 
			s5.rotationX = 90; 
			s5.y = CUBE_SIZE * .5; 
			s6.rotationX = 90; 
			s6.y = -CUBE_SIZE * .5;  


			cube.x = 250; 
			cube.y = 200;  


		private function createSide():Sprite { 
			var s:Sprite = new Sprite();, 0x000000); * 0xFFFFFF, .15); -CUBE_SIZE * .5, -CUBE_SIZE * .5, CUBE_SIZE, CUBE_SIZE);; 
			return s; 

		private function frameHandler(event:Event):void { 
			cube.rotationY += 5; 
			cube.rotationX += 2; 
Posted by