Loading, Filtering, and Saving Images with Flash Player 10

Still playing with the new features of Flash Player 10.

This example uses a halftone Pixel Bender filter created by Justin Everett-Church which you can check out here. It also uses the new additions to the FileReference api to upload and download files.

To use, just click on “load image” and browse for an image file to upload. Make sure the file is under 50k or the application will just fail silently. Once the image is uploaded the halftone filter will be automatically applied. Use the sliders to make adjustments and the color picker to choose a different background color. Once satisfied with your creation, click on save image to save the altered file back on your own computer. Amazing, even if I do say so myself.

Incidentally, if your image is larger than the viewing area, you can drag it around to view the entire thing.

With Flash CS4/Flash Player 10 Image and Sound editing applications are going to be so freaking easy to build (not sure about video yet – that may take a bit of finagling).

Again, to view the example, you’ll need Flash Player 10 installed:

[kml_flashembed movie=”http://blog.onebyonedesign.com/wp-content/uploads/2008/06/halftone.swf” height=”500″ width=”500″ /]

And the code to create the above (I wouldn’t leave ya hangin’):

package {

	import com.adobe.images.JPGEncoder;
	import com.onebyonedesign.ui.events.ColorEvent;
	import com.onebyonedesign.ui.events.ValueSliderEvent;
	import com.onebyonedesign.ui.OBO_ColorPicker;
	import com.onebyonedesign.ui.OBO_ValueSlider;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.Shader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.DropShadowFilter;
	import flash.filters.ShaderFilter;
	import flash.geom.Rectangle;
	import flash.net.FileFilter;
	import flash.net.FileReference;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.text.AntiAliasType;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.utils.ByteArray;
	
	/**
	* Load image manipulate halftone effect then save image.
	* @author Devon O.
	*/
	[SWF(width="500", height="500", backgroundColor="#869CA7", framerate="31")]
	public class main extends Sprite {
		
		[Embed(source="halftone.pbj", mimeType="application/octet-stream")]
		private var ShaderData:Class;
		
		private var _fileRef:FileReference;
		
		private var _shader:Shader;
		private var _shaderFilter:ShaderFilter;
		private var _image:Sprite = new Sprite();	
		private var _dragBounds:Rectangle = new Rectangle();
		private var _imgWidth:Number;
		private var _imgHeight:Number;
		
		// UI
		private var _imageHolder:Sprite;
		private var _controlHolder:Sprite;
		private var _imageMask:Sprite;
		private var _radiusControl:OBO_ValueSlider;
		private var _offsetControl:OBO_ValueSlider;
		private var _bgcolorControl:OBO_ColorPicker;
			
		public function main():void {
			_shader = new Shader();
			_shader.byteCode = new ShaderData();
			_shaderFilter = new ShaderFilter(_shader);
			
			_fileRef = new FileReference();
			
			var titleText:TextField = new TextField();
			titleText.defaultTextFormat = new TextFormat("_sans", 30, 0x000000, true);
			titleText.selectable = false;
			titleText.antiAliasType = AntiAliasType.ADVANCED;
			titleText.mouseEnabled = false;
			titleText.text = "Half Tone Image Filter";
			titleText.autoSize = TextFieldAutoSize.LEFT;
			titleText.x = 40;
			titleText.y = 350;
			titleText.rotationZ = -90;
			titleText.alpha = .2
			addChild(titleText);
			
			init();
		}
		
		private function init():void {
			initUI();
		}
		
		private function initUI():void {
			var shadow:DropShadowFilter = new DropShadowFilter(2, 90);
			var format:TextFormat = new TextFormat("_sans", 11);
			
			_imageHolder = new Sprite();
			_imageHolder.graphics.beginFill(0xFFFFCC);
			_imageHolder.graphics.drawRect(0, 0, 350, 350);
			_imageHolder.graphics.endFill();
			_imageHolder.filters = [shadow];
			_imageHolder.x = 75;
			_imageHolder.y = 20;
			addChild(_imageHolder);
			
			_imageMask = new Sprite();
			_imageMask.graphics.beginFill(0x232323);
			_imageMask.graphics.drawRect(0, 0, 350, 350);
			_imageMask.graphics.endFill();
			_imageMask.visible = false;
			_imageHolder.addChild(_imageMask);
			
			_controlHolder = new Sprite();
			_controlHolder.graphics.beginFill(0xEEEEE6);
			_controlHolder.graphics.drawRoundRect(0, 0, 300, 90, 10, 10);
			_controlHolder.graphics.endFill();
			_controlHolder.x = 100;
			_controlHolder.y = 380;
			_controlHolder.filters = [shadow];
			addChild(_controlHolder);
			
			var radText:TextField = new TextField();
			radText.mouseEnabled = false;
			radText.selectable = false;
			radText.defaultTextFormat = format;
			radText.autoSize = TextFieldAutoSize.LEFT;
			radText.antiAliasType = AntiAliasType.ADVANCED;
			radText.text = "halftone radius:";
			radText.x = 10;
			radText.y = 5;
			_controlHolder.addChild(radText);
			
			_radiusControl = new OBO_ValueSlider(80, 1, 50, 5);
			_radiusControl.x = 10;
			_radiusControl.y = int(radText.y + radText.height + 5);
			_radiusControl.addEventListener(ValueSliderEvent.DRAG, radiuschangeHandler);
			_controlHolder.addChild(_radiusControl);
			
			var offText:TextField = new TextField();
			offText.mouseEnabled = false;
			offText.selectable = false;
			offText.defaultTextFormat = format;
			offText.autoSize = TextFieldAutoSize.LEFT;
			offText.antiAliasType = AntiAliasType.ADVANCED;
			offText.text = "halftone offset:";
			offText.x = 10;
			offText.y = 50;
			_controlHolder.addChild(offText);
			
			_offsetControl = new OBO_ValueSlider(80, .1, 2, .5);
			_offsetControl.x = 10;
			_offsetControl.y = int(offText.y + offText.height + 5);
			_offsetControl.addEventListener(ValueSliderEvent.DRAG, offsetchangeHandler);
			_controlHolder.addChild(_offsetControl);
			
			var bgcolorText:TextField = new TextField();
			bgcolorText.mouseEnabled = false;
			bgcolorText.selectable = false;
			bgcolorText.defaultTextFormat = format;
			bgcolorText.autoSize = TextFieldAutoSize.LEFT;
			bgcolorText.antiAliasType = AntiAliasType.ADVANCED;
			bgcolorText.text = "background color:";
			bgcolorText.x = 120;
			bgcolorText.y = 5;
			_controlHolder.addChild(bgcolorText);
			
			_bgcolorControl = new OBO_ColorPicker(20, 20, 0xFFFFCC);
			_bgcolorControl.x = bgcolorText.x + bgcolorText.width + 15;
			_bgcolorControl.y = 5;
			_bgcolorControl.addEventListener(ColorEvent.COLOR_SELECT, bgColorChange);
			_bgcolorControl.filters = [new DropShadowFilter(1, 90, 0x000000, .8, 2, 2)];
			_controlHolder.addChild(_bgcolorControl);
			
			var loadBtn:EasyButton = new EasyButton("Load Image");
			loadBtn.x = 120;
			loadBtn.y = 60;
			loadBtn.addEventListener(MouseEvent.CLICK, browseforImage);
			_controlHolder.addChild(loadBtn);
			
			var saveBtn:EasyButton = new EasyButton("Save Image");
			saveBtn.x = 210;
			saveBtn.y = 60;
			saveBtn.addEventListener(MouseEvent.CLICK, saveImage);
			_controlHolder.addChild(saveBtn);
		}
		
		private function browseforImage(event:MouseEvent):void {
			_fileRef.addEventListener(Event.SELECT, loadImage);
			_fileRef.addEventListener(Event.COMPLETE, onUpload);
			var filter:FileFilter = new FileFilter("Images (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg;*.jpeg;*.gif;*.png");
			_fileRef.browse([filter]);
		}
		
		private function loadImage(event:Event):void {
			_fileRef.removeEventListener(Event.SELECT, loadImage);
			// 51200 = 50k  -  61440 = 60k
			// over 50k fails silently
			if (_fileRef.size < 51200) 
				_fileRef.load();
		}
		
		private function onUpload(event:Event):void {
			_fileRef.removeEventListener(Event.COMPLETE, onUpload);
			var l:Loader = new Loader();
			l.contentLoaderInfo.addEventListener(Event.COMPLETE, imageloadHandler);
			l.loadBytes(_fileRef.data);
		}
		
		private function imageloadHandler(event:Event):void {
			
			if (_image.willTrigger(MouseEvent.MOUSE_DOWN))
				_image.removeEventListener(MouseEvent.MOUSE_DOWN, dragImage);
			event.currentTarget.removeEventListener(Event.COMPLETE, imageloadHandler);
			
			try {
				_image.removeChild(_image.getChildAt(0));
			}
			catch (e:Error){ }
			
			_imgWidth = event.currentTarget.content.width;
			_imgHeight = event.currentTarget.content.height;
			_image.mask = _imageMask;
			
			_dragBounds.left = (_imgWidth < _imageHolder.width) ? 0 : _imageHolder.width - _imgWidth;
			_dragBounds.top = (_imgHeight < _imageHolder.height) ? 0 : _imageHolder.height - _imgHeight;
			_dragBounds.width = (_imgWidth < _imageHolder.width) ? _imageHolder.width - _imgWidth : _imgWidth - _imageHolder.width;
			_dragBounds.height = (_imgHeight < _imageHolder.height) ? _imageHolder.height - _imgHeight : _imgHeight - _imageHolder.height;
			_image.addChild(event.currentTarget.content);
			
			_image.addEventListener(MouseEvent.MOUSE_DOWN, dragImage);
			
			_image.x = _image.y = 0;
			_imageHolder.addChild(_image);
			
			applyFilter();
		}
		
		private function dragImage(event:MouseEvent):void {
			stage.addEventListener(MouseEvent.MOUSE_UP, stopdragImage);
			_image.startDrag(false, _dragBounds);
		}
		
		private function stopdragImage(event:MouseEvent):void {
			stage.removeEventListener(MouseEvent.MOUSE_UP, stopdragImage);
			_image.stopDrag();
		}
		
		private function applyFilter():void {
			_shader.data.radius.value = [_radiusControl.value];
			_shader.data.offset.value = [_offsetControl.value];
			_image.filters = [_shaderFilter];
		}
		
		private function radiuschangeHandler(event:ValueSliderEvent):void {
			_shader.data.radius.value = [int(event.value)];
			_image.filters = [_shaderFilter];
		}
		
		private function offsetchangeHandler(event:ValueSliderEvent):void {
			_shader.data.offset.value = [event.value];
			_image.filters = [_shaderFilter];
		}
		
		private function bgColorChange(event:ColorEvent):void {
			_imageHolder.graphics.clear();
			_imageHolder.graphics.beginFill(event.color);
			_imageHolder.graphics.drawRect(0, 0, 350, 350);
			_imageHolder.graphics.endFill();
		}
		
		private function saveImage(event:MouseEvent):void {
			var bmp:BitmapData = new BitmapData(_imgWidth, _imgHeight, true, uint("0xFF" + _bgcolorControl.currentColorString));
			_image.mask = null;
			bmp.draw(_image);
			_image.mask = _imageMask;
			var encoder:JPGEncoder = new JPGEncoder(100);
			var saveBytes:ByteArray = encoder.encode(bmp);
			_fileRef.save(saveBytes, "saved_from_onebyonedesign.jpg");
		}
	}
}

import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.text.AntiAliasType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

internal class EasyButton extends SimpleButton {
	
	private static const UP_COLOR	:uint = 0xCCCCCC;
	private static const OVER_COLOR	:uint = 0x999999;
	private static const DOWN_COLOR	:uint = 0x869CA7;
	
	private var _label				:String;
		
	public function EasyButton(label:String):void {
		_label = label;
		makeButton();
	}
		
	private function makeButton():void {
		upState = null;
		overState = null;
		downState = null;
		hitTestState = null;
		upState = createState(UP_COLOR);
		overState = createState(OVER_COLOR);
		downState = createState(DOWN_COLOR);
		hitTestState = upState;
	}
		
	private function createState(color:uint):Sprite {
		var s:Sprite = new Sprite();
		s.graphics.beginFill(color);
		s.graphics.drawRect(0, 0, 80, 17);
		s.graphics.endFill();
		var labelText:TextField = createLabel();
		labelText.x = 5;
		s.addChild(labelText);
		
		return s;
	}
		
	private function createLabel():TextField {
		var tf:TextField = new TextField();
		tf.antiAliasType = AntiAliasType.ADVANCED;
		tf.autoSize = TextFieldAutoSize.LEFT;
		tf.selectable = false;
		tf.mouseEnabled = false;
		tf.defaultTextFormat = new TextFormat("_sans", 11);
		tf.text = _label;
		tf.antiAliasType = AntiAliasType.ADVANCED;
		
		return tf;
	}
	
	public function set label(s:String):void {
		_label = s;
		makeButton();
	}
}
Date: