Forked from: xlune's forked from: 画像のアウトラインを一筆書きじゃない diff:3 forked from: forked from: 画像のアウトラインを一筆書きじゃない doodoo forked:0favorite:0lines:188license : All rights reserved modified : 2009-05-22 14:02:58 Embed Tweet // forked from xlune's 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 = 100; //描画スピード private var _speed:uint = 100; //閾値 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; } } } Code Fullscreen Preview Fullscreen Point.distance LoaderContext sort Point Boolean visible shift Error graphics Event.COMPLETE removeEventListener alpha URLRequest Vector height width Math.sqrt addChild trace addEventListener