Techblog

Tech Blog

Our latest geek adventures!

Posts Tagged ‘local file system’

4 May Load, modify and save local images with Flash Player 10

One of the cool new things about Flash Player 10 is that you now have access to the local file system. This means that you can load, modify and save files directly on the client side without any server interaction. Mike Chambers wrote a post about reading and writing text files and I was wondering if it was possible to do this with image files too.
thumbr here

Publish Flash Player 10 content

To test this, I first needed a way to make my Flex Builder compile Flash Player 10 content. I found a rather old post by Andrei Ionescu about building Flash Player 10 applications that told me exactly what I was looking for. I downloaded the latest Flex SDK (3.3) from Adobe’s Flex Download page, followed the tutorial and I was ready to go.

Load image from local file system

Reading a local file was no biggie, just copied and pasted the code from Mike’s sample. What I needed now was a way to convert the loaded data into an image. As usual Tim helped me out by sending me a snippet:

var data:ByteArray = fileRef['data'];
var loader:Loader = new Loader();
loader.loadBytes(data);
addChild(loader);

Modify image

Now that I could load the image, I wanted to modify it before having it rendered. I extended the snippet to use BitmapData and a Matrix to resize the image to a thumb image (240×180px).

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onDataLoadComplete);
loader.loadBytes(loadFileRef.data);
 
private function onDataLoadComplete(e:Event):void {
  var bitmapData:BitmapData = Bitmap(e.target.content).bitmapData;
  var matrix:Matrix = new Matrix();
  matrix.scale(THUMB_WIDTH/bitmapData.width, THUMB_HEIGHT/bitmapData.height);
 
  imageView.graphics.clear();
  imageView.graphics.beginBitmapFill(bitmapData, matrix, false);
  imageView.graphics.drawRect(0, 0, THUMB_WIDTH, THUMB_HEIGHT);
  imageView.graphics.endFill();
}

Save image to local file system

Now that it’s possible to load and modify an image, saving it is the last step. To save an image, it has to be encoded to a ByteArray. I used the open source as3corelib to help me out. Saving the ByteArray to a file is rather straight forward.

Update 1: You don’t need to use the as3corelib anymore, Flex 3.3 has it own JPEGEncoder.

var encoder:JPEGEncoder = new JPEGEncoder();
var rawBytes:ByteArray = encoder.encode(bitmapData);
 
var saveFileRef:FileReference = new FileReference();
saveFileRef.save(rawBytes);

Update 2: Thibault Imbert figured out a way to speed up JPEG encoding using the new FP10 Vector class. Good stuff!

Update 3: You can now also use Alchemy for the encoding. It’s much, much faster then the other options! See this post from Jens Krause: Speed up JPEG encoding using Alchemy

This sample shows that it’s not only possible to load, modify and save images directly from the local file system, but that it’s actually very simple to do so. Add some PixelBender image processing power to the game and you almost have a Photoshop killer running completly client side!

Code sample

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundGradientColors="[0xFFFFFF,0xFFFFFF]" backgroundColor="0xFFFFFF">
 
	<mx:Script>
		<![CDATA[
			import mx.graphics.codec.JPEGEncoder;
			import mx.binding.utils.BindingUtils;
			import mx.core.UIComponent;
 
			import flash.net.FileReference;
			import flash.net.FileFilter;
			import flash.events.IOErrorEvent;
			import flash.events.Event;
			import flash.utils.ByteArray;
 
			private var loadFileRef:FileReference;
 
			private static const FILE_TYPES:Array = [new FileFilter("Image Files", "*.jpg;*.jpeg;*.gif;*.png;*.JPG;*.JPEG;*.GIF;*.PNG")];
			private static const THUMB_WIDTH:uint = 240;
			private static const THUMB_HEIGHT:uint = 180;
 
			private function loadFile():void {
				loadFileRef = new FileReference();
				loadFileRef.addEventListener(Event.SELECT, onFileSelect);
				loadFileRef.browse();
			}
 
			private function saveFile():void {		
				var bitmapData:BitmapData = new BitmapData(THUMB_WIDTH, THUMB_HEIGHT);
				bitmapData.draw(imageView);
 
				var encoder:JPEGEncoder = new JPEGEncoder();
				var rawBytes:ByteArray = encoder.encode(bitmapData);
 
 				var saveFileRef:FileReference = new FileReference();
				saveFileRef.save(rawBytes);
			}
 
			private function onFileSelect(e:Event):void {
				loadFileRef.addEventListener(Event.COMPLETE, onFileLoadComplete);
				loadFileRef.load();
			}
 
			private function onFileLoadComplete(e:Event):void {
			   	var loader:Loader = new Loader();
			   	loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onDataLoadComplete);
			   	loader.loadBytes(loadFileRef.data);
 
				loadFileRef = null;
			}
 
			private function onDataLoadComplete(e:Event):void {
				var bitmapData:BitmapData = Bitmap(e.target.content).bitmapData;
 
                var matrix:Matrix = new Matrix();
                matrix.scale(THUMB_WIDTH/bitmapData.width, THUMB_HEIGHT/bitmapData.height);
 
				imageView.graphics.clear();
				imageView.graphics.beginBitmapFill(bitmapData, matrix, false); 
				imageView.graphics.drawRect(0, 0, THUMB_WIDTH, THUMB_HEIGHT);
				imageView.graphics.endFill(); 
 
				saveButton.enabled = true;
			}
 
		]]>
	</mx:Script>
	<mx:Panel title="Create thumb image" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
		<mx:VBox>
			<mx:Canvas id="imageView" width="240" height="180" borderThickness="1" borderColor="#CCCCCC" borderStyle="solid"/>
			<mx:HBox paddingTop="5" borderThickness="1">
				<mx:Button label="Load image" click="loadFile()"/>
				<mx:Button label="Save image" click="saveFile()" id="saveButton" enabled="false"/>
			</mx:HBox>
		</mx:VBox>
	</mx:Panel>
</mx:Application>

11 Comments - Tags: , , , , , , ,