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

forked from: 画像のアウトラインを一筆書きじゃない

// forked from xlune's 画像のアウトラインを一筆書き
package {
	import __AS3__.vec.Vector;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.CapsStyle;
	import flash.display.Graphics;
	import flash.display.JointStyle;
	import flash.display.LineScaleMode;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	
	[SWF(width=465, height=465, frameRate=15, backgroundColor=0xFFFFFF)]
	public class main extends Sprite
	{
		//画面幅
		private var _width:uint = 465;
		//画面高さ
		private var _height:uint = 465;
		//精度
		private var _prec:uint = 1;
		//描画スピード
		private var _speed:uint = 3;
		//閾値
		private var _threshold:uint = 0xCC;
		//ガイド画像
		private var _imgUrl:String = 'http://farm4.static.flickr.com/3366/3409173374_d1a4af8142.jpg';
		
		private var _img:Loader;
		private var _guide:BitmapData;
		private var _canvas:Sprite;
		private var _gp:Graphics;
		private var _pointMap:Vector.<Vector.<Boolean>>;
		private var _pointGroups:Vector.<Vector.<Point>>;
		private var _drowGroup:Vector.<Point>;
		private var _basePoint:Point;
		private var _closePoint:Point;
		
		/**
		 * コンストラクタ
		 */
		public function main()
		{
			var request:URLRequest = new URLRequest(_imgUrl);
			var context:LoaderContext = new LoaderContext(true);
			_img = new Loader();
			_img.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
			_guide = new BitmapData(_width, _height, false, 0x00FFFFFF);
			_canvas = new Sprite();
			_gp = _canvas.graphics;
			_gp.lineStyle(1, 0xFF0000, 1, true, LineScaleMode.NONE, CapsStyle.ROUND, JointStyle.MITER, 2);
			
			try {
				_img.load(request, context);
			} catch (error:Error) {
				trace("image load failed.");
			}
		}
		
		/**
		 * Event Complete Handler
		 */
		private function completeHandler(event:Event):void
		{
			_img.x = _width / 2 - _img.width / 2;
			_img.y = _height / 2 - _img.height / 2;
			_img.alpha = 0.1;
			
			var gMatrix:Matrix = new Matrix();
			gMatrix.tx = _img.x;
			gMatrix.ty = _img.y;
			_guide.draw(_img, gMatrix);
			
			makePoints();
			
			addChild(_img);
			addChild(_canvas);
			this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
			
		}
		
		/**
		 * Event EnterFrame Handler
		 */
		private function enterFrameHandler(event:Event):void
		{
			if(_pointGroups.length > 0 || _drowGroup.length > 0)
			{
				var drowPoint:Point;
				if(!_drowGroup || _drowGroup.length == 0)
				{
					_basePoint = new Point(0, 0);
					_drowGroup = Vector.<Point>(_pointGroups.shift());
					_drowGroup.sort(drowPointSort);
					drowPoint = Point(_drowGroup.shift());
					if(_closePoint)
					{
						_gp.lineTo(_closePoint.x, _closePoint.y);
					}
					_gp.moveTo(drowPoint.x, drowPoint.y);
					_closePoint = _basePoint = drowPoint;
				}
				else
				{
					_drowGroup.sort(drowPointSort);
					drowPoint = Point(_drowGroup.shift());
					if(Point.distance(_basePoint, drowPoint) > Math.sqrt(_prec*_prec*2))
					{
						if(_closePoint)
						{
							_gp.lineTo(_closePoint.x, _closePoint.y);
						}
						_gp.moveTo(drowPoint.x, drowPoint.y);
						_closePoint = drowPoint;
					}
					else
					{
						_gp.lineTo(drowPoint.x, drowPoint.y);
					}
					_basePoint = drowPoint;
				}
			}
			else
			{
				_img.visible = false;
				this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			}
		}
		
		/**
		 * 境界点ソート
		 */
		private function drowPointSort(a:Point, b:Point):int
		{
			var numA:Number = Point.distance(_basePoint, a);
			var numB:Number = Point.distance(_basePoint, b);
			if(numA > numB)
			{
				return 1;
			}
			else if(numA < numB)
			{
				return -1;
			}
			return 0;
		}
		
		/**
		 * 境界点生成
		 */
		private function makePoints():void
		{
			var groupNum:uint = 0;
			_pointMap = new Vector.<Vector.<Boolean>>(uint(_height/_prec));
			_pointGroups = new Vector.<Vector.<Point>>();
			for(var i:uint=0,iMax:uint=_pointMap.length; i<iMax; i++)
			{
				_pointMap[i] = new Vector.<Boolean>(uint(_width/_prec));
			}
			
			for(i=0,iMax=_pointMap.length; i<iMax; i++)
			{
				for(var j:uint=0,jMax:uint=_pointMap[i].length; j<jMax; j++)
				{
					if(_pointMap[i][j] != true && isFillPoint(j * _prec, i * _prec))
					{
						_pointGroups[groupNum] = new Vector.<Point>();
						groupAgent(j, i, groupNum++);
					}
				}
			}
		}
		
		/**
		 * 境界点をグループ化
		 */
		private function groupAgent(xNum:int, yNum:int, groupNum:uint):void
		{
			if(0 <= xNum && xNum < uint(_width/_prec)
				&& 0 <= yNum  && yNum < uint(_height/_prec))
			{
				if(_pointMap[yNum][xNum] != true)
				{
					_pointMap[yNum][xNum] = true;
					if(isFillPoint(xNum * _prec, yNum * _prec)){
						if(isUniquePoint(xNum * _prec, yNum * _prec))
						{
							_pointGroups[groupNum].push(new Point(xNum * _prec, yNum * _prec));
						}
						groupAgent(xNum, yNum-1, groupNum);
						groupAgent(xNum+1, yNum, groupNum);
						groupAgent(xNum, yNum+1, groupNum);
						groupAgent(xNum-1, yNum, groupNum);
					}
				}
			}
		}
		
		/**
		 * 境界点を抽出
		 */
		private function isUniquePoint(posX:int, posY:int):Boolean
		{
			if(isFillPoint(posX, posY))
			{
				if(!isFillPoint(posX, posY-_prec)
					|| !isFillPoint(posX+_prec, posY)
					|| !isFillPoint(posX, posY+_prec)
					|| !isFillPoint(posX-_prec, posY))
				{
					return true;
				}
			}
			return false;
		}
		
		/**
		 * 2値化
		 */
		private function isFillPoint(posX:int, posY:int):Boolean
		{
			if(posX < 0 || posX > _width) return false;
			if(posY < 0 || posY > _height) return false;
			var color:uint = _guide.getPixel(posX, posY);
			color = (((color >> 16) & 0xff) + ((color >> 8) & 0xff) + (color & 0xff)) / 3;
			if(color < _threshold) return true;
			return false;
		}
	}
}