In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

ToyCamera トイカメラ風エフェクト

2010.04.22 保存機能追加
/**
 * Copyright fernet ( http://wonderfl.net/user/fernet )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xaas
 */

// 2010.04.22 保存機能追加
package 
{
	import com.bit101.components.PushButton;
	import com.bit101.components.HUISlider;
	import com.bit101.components.CheckBox;
	import com.bit101.components.RadioButton;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	[SWF(width=465,height=465,backgroundColor=0xaaaaaa)]
	
	/**
	 * ...
	 * @author fernet
	 */
	public class Main extends Sprite 
	{
		private var _imgbox:Sprite = new Sprite;
		private var _lastLoad:Bitmap;
		
		private var _ctrlCont:CheckBox;
		private var _ctrlContLevel:HUISlider;
		private var _ctrlSat:CheckBox;
		private var _ctrlSatLevel:HUISlider;
		private var _ctrlTunnel:CheckBox;
		private var _ctrlTunnelSize:HUISlider;
		private var _ctrlTunnelRatio:HUISlider;
		private var _ctrlNoise:CheckBox;
		private var _ctrlNoiseLevel:HUISlider;
		private var _ctrlCA:CheckBox;
		private var _ctrlCALevel:HUISlider;
		private var _ctrlBlur:CheckBox;
		private var _ctrlBlurLevel:HUISlider;
		
		public function Main():void 
		{
			Wonderfl.capture_delay(30);
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			
			addChild(_imgbox);
			
			_imgbox.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
				_imgbox.startDrag();
			});
			_imgbox.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void {
				_imgbox.stopDrag();
			});
			
			var y:int = 0;
			var imloader:LocalImageLoader = new LocalImageLoader;
			new PushButton(stage, 0, y, "Browse Image", function(e:Event):void {
				imloader.load(_onBitmap);
			});
			y += 30;
			
			_ctrlCont = new CheckBox(stage, 0, y, "Contrast", _onChangeControl); y += 10;
			_ctrlCont.selected = true;
			_ctrlContLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
			_ctrlContLevel.setSliderParams(0, 2, 0.8);
			y += 20;
			
			_ctrlSat = new CheckBox(stage, 0, y, "Saturation", _onChangeControl); y += 10;
			_ctrlSat.selected = true;
			_ctrlSatLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
			_ctrlSatLevel.setSliderParams(0.5, 3, 1.2);
			y += 20;
			
			_ctrlTunnel = new CheckBox(stage, 0, y, "TunnelEffect", _onChangeControl); y += 10;
			_ctrlTunnel.selected = true;
			_ctrlTunnelSize = new HUISlider(stage, 0, y, "Size", _onChangeControl); y += 10;
			_ctrlTunnelSize.setSliderParams(2, 5, 3);
			_ctrlTunnelRatio = new HUISlider(stage, 0, y, "Ratio", _onChangeControl); y += 10;
			_ctrlTunnelRatio.setSliderParams(1, 254, 210);
			y += 20;
			
			_ctrlNoise = new CheckBox(stage, 0, y, "Noise", _onChangeControl); y += 10;
			_ctrlNoise.selected = true;
			_ctrlNoiseLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
			_ctrlNoiseLevel.setSliderParams(0, 255, 30);
			y += 20;
			
			_ctrlCA = new CheckBox(stage, 0, y, "ChromaticAberration", _onChangeControl); y += 10;
			_ctrlCA.selected = true;
			_ctrlCALevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
			_ctrlCALevel.setSliderParams(0, 10, 2);
			y += 20;
			
			_ctrlBlur = new CheckBox(stage, 0, y, "Blur", _onChangeControl); y += 10;
			_ctrlBlur.selected = true;
			_ctrlBlurLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
			_ctrlBlurLevel.setSliderParams(0, 20, 1.5);
			y += 20;
			
			var formatJpg:RadioButton = new RadioButton(stage, 0,  y, "JPEG", true);
			var formatPng:RadioButton = new RadioButton(stage, 50, y, "PNG", false);
			y += 20;
			new PushButton(stage, 0, y, "Save Image", function(e:Event):void {
				if (!_lastLoad) return;
				var encoder:LocalImageEncoder = new LocalImageEncoder;
				var bd:BitmapData = (_imgbox.getChildAt(0) as Bitmap).bitmapData;
				var now:String = new DateFormat("%Y%m%d_%H%M%S").make();
				formatJpg.selected ?
					encoder.saveJpg(bd, "toycamera_" + now + ".jpg"):
					encoder.savePng(bd, "toycamera_" + now + ".png");
			});
		}
		
		private function _onBitmap(bmp:Bitmap):void
		{
			_lastLoad = bmp;
			_process();
		}
		
		private function _onChangeControl(e:Event):void
		{
			if (_lastLoad)
				_process();
		}
		
		private function _onClickSave(e:Event):void
		{
			if (_lastLoad)
			{
				var encoder:LocalImageEncoder = new LocalImageEncoder;
				_process();
			}
		}
		
		private function _process():void
		{
			var bd:BitmapData = _lastLoad.bitmapData.clone();
			var tc:ToyCamera = new ToyCamera(bd);
			
			if(_ctrlCont.selected)
				tc.setContrast(_ctrlContLevel.value);
			if (_ctrlSat.selected)
				tc.setSaturation(_ctrlSatLevel.value);
			if(_ctrlTunnel.selected)
				tc.setTunnel(_ctrlTunnelRatio.value, _ctrlTunnelSize.value);
			if(_ctrlCA.selected)
				tc.setChromaticAberration(_ctrlCALevel.value);
			if(_ctrlNoise.selected)
				tc.setNoise(_ctrlNoiseLevel.value);
			if(_ctrlBlur.selected)
				tc.setBlur(_ctrlBlurLevel.value);
			
			if (_imgbox.numChildren)
				_imgbox.removeChildAt(0);
				
			_imgbox.addChild(new Bitmap(tc.data));
		}
	}
}

class ToyCamera {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.filters.BlurFilter;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.utils.ByteArray;
	
	private var _canvas:BitmapData;
	
	public function ToyCamera(bd:BitmapData)
	{
		_canvas = bd;
		_canvas.lock();
	}
	
	/**
	 * コントラスト
	 */
	public function setContrast(c:Number):void
	{
		var mtx:Array = [
			c+1, 0, 0, 0, -c*0x80,
			0, c+1, 0, 0, -c*0x80,
			0, 0, c+1, 0, -c*0x80,
			0, 0, 0,   1, 0
		];
		var filter:ColorMatrixFilter = new ColorMatrixFilter(mtx);
		_canvas.applyFilter(_canvas, _canvas.rect, new Point, filter);
	}
	
	/**
	 * 彩度
	 */
	public function setSaturation(s:Number = 3):void
	{
		var a:Number = s * 2 / 3 + 1 / 3;
		var b:Number = (1 - a) / 2;
		var mtx:Array = [
			a, b, b, 0, 0,
			b, a, b, 0, 0,
			b, b, a, 0, 0,
			0, 0, 0, 1, 0
		];
		var filter:ColorMatrixFilter = new ColorMatrixFilter(mtx);
		_canvas.applyFilter(_canvas, _canvas.rect, new Point, filter);
	}
	
	/**
	 * トンネル
	 */
	public function setTunnel(ratio:int, size:Number):void
	{
		var h:int = _canvas.height, w:int = _canvas.width;
		var larger:int = w > h ? w : h;
		var shape:Shape = new Shape;
		shape.graphics.beginGradientFill(GradientType.RADIAL,
			[0x0, 0x0, 0x0],
			[0.0, 0.0, 1.0],
			[0x00, ratio, 0xFF]
		);
		shape.graphics.drawCircle(0, 0, larger / 2);
		var mtx:Matrix = new Matrix(
			size, 0,
			0, size,
			w / 2, h / 2);
		_canvas.draw(shape, mtx);
	}
	
	/**
	 * ぼかし
	 */
	public function setBlur(lv:Number):void
	{
		var src:BitmapData = _canvas;
		var blur:BlurFilter = new BlurFilter(lv, lv, 1);
		src.applyFilter(src, src.rect, new Point, blur);
	}
	
	/**
	 * 色収差
	 * 赤チャンネルをlv%縮小し、青チャンネルをlv%拡大してる
	 */
	public function setChromaticAberration(lv:Number):void
	{
		lv /= 100;
		
		var src:BitmapData = _canvas.clone();
		var dst:BitmapData = _canvas;
		var w:int = dst.width, h:int = dst.height;
		
		for (var y:int=0; y<h; y++) {
			for (var x:int = 0; x<w; x++) {
				var r:uint = src.getPixel(_calcPx(x,w,+lv), _calcPx(y,h,+lv)) & 0xff0000;
				var g:uint = src.getPixel(_calcPx(x,w,  0), _calcPx(y,h,  0)) & 0x00ff00;
				var b:uint = src.getPixel(_calcPx(x,w,-lv), _calcPx(y,h,-lv)) & 0x0000ff;
				dst.setPixel(x, y, r|g|b);
			}
		}
	}
	
	// 中心からlen%外側の座標
	private function _calcPx(pos:int, max:int, lv:Number):int
	{
		var ret:int = (pos * (1 + lv)) - (max / 2 * lv);
		if (ret < 0) ret = 0;
		if (ret > max - 1) ret = max - 1;
		return ret;
	}
	
	/**
	 * ノイズ
	 * 0xC0に近いほど粒状感が出やすいらしい?
	 */
	public function setNoise(level:Number):void
	{
		var src:BitmapData = _canvas;
		var noise:BitmapData = new BitmapData(src.width, src.height, true, 0x00ffffff);
		noise.noise(123, 0, 255, 4 | 2 | 1, true);
		
		for (var y:int=0; y<src.height; y++) {
			for (var x:int = 0; x < src.width; x++) {
				var col:uint = src.getPixel(x, y);
				var gray:int = ((col >> 16) + (col >> 8 & 0xff) + (col & 0xff)) / 3;
				var alpha:int = (0xc0 - Math.abs(0xc0 - gray)) / 0xc0 * level;
				var noisecol:uint = noise.getPixel(x,y)
				noise.setPixel32(x, y, (alpha << 24) | noisecol);
			}
		}
		
		src.copyPixels(noise, noise.rect, new Point, null, new Point, true);
	}
	
	public function get data():BitmapData
	{
		_canvas.unlock();
		return _canvas;
	}
}

class LocalImageLoader
{
	import flash.display.Loader;
	import flash.display.Bitmap;
	import flash.net.FileReference;
	import flash.net.FileFilter;
	import flash.events.Event;

	private var _callback:Function = function(bmp:Bitmap):void{};
	private var _file:FileReference = new FileReference;
	private var _loader:Loader = new Loader;
	
	public function LocalImageLoader()
	{
		_file.addEventListener(Event.SELECT, _onSelect);
		_file.addEventListener(Event.COMPLETE, _onComplete);
		_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _finish);
	}
	
	public function load(callback:Function):void
	{
		_callback = callback;
		_file.browse([new FileFilter("Images", "*.jpg;*.jpeg;*.gif;*.png")]);
	}
	
	private function _onSelect(e:Event):void
	{
		_file.load();
	}
	
	private function _onComplete(e:Event):void
	{
		_loader.loadBytes(_file.data);
	}
	
	private function _finish(e:Event):void
	{
		_callback(_loader.content);
	}
}

class LocalImageEncoder
{
	import flash.net.FileReference;
	import flash.display.BitmapData;
	import flash.utils.ByteArray;
	import com.adobe.images.PNGEncoder;
	import com.adobe.images.JPGEncoder;
	
	private var _file:FileReference = new FileReference;
	
	public function savePng(bd:BitmapData, filename:String = null):void
	{
		_saveByteArray(PNGEncoder.encode(bd), filename);
	}
	
	public function saveJpg(bd:BitmapData, filename:String = null, quality:int = 95):void
	{
		var enc:JPGEncoder = new JPGEncoder(quality);
		_saveByteArray(enc.encode(bd), filename);
	}
	
	private function _saveByteArray(ba:ByteArray, filename:String = null):void
	{
		_file.save(ba, filename);
	}
}

class DateFormat
{
	private var _format:String;
	public function DateFormat(format:String)
	{
		_format = format;
	}
	
	public function make(time:Date = null):String
	{
		if (time == null) time = new Date;
		var ret:String = _format.replace(/%(.)/g, function():String {
			switch(arguments[1])
			{
				case "Y": return time.getFullYear().toString();
				case "m": return ("0" + time.getMonth().toString()).substr(-2);
				case "d": return ("0" + time.getDate().toString()).substr(-2);
				case "H": return ("0" + time.getHours().toString()).substr(-2);
				case "M": return ("0" + time.getMinutes().toString()).substr(-2);
				case "S": return ("0" + time.getSeconds().toString()).substr( -2);
			}
			return arguments[0];
		});
		return ret;
	}
}