Forked from: chutaicho's Painting diff:2 forked from: Painting 画像を抽象絵画風に描画 George0rwell.. forked:0favorite:0lines:241license : MIT License modified : 2012-04-04 15:29:30 Embed Tweet // forked from chutaicho's Painting /** 画像を抽象絵画風に描画 */ package { import __AS3__.vec.Vector; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.TimerEvent; import flash.geom.ColorTransform; import flash.net.URLRequest; import flash.system.LoaderContext; import flash.utils.Timer; [SWF(backgroundColor="0x000000", frameRate="40")] public class AbstractPainting extends Sprite { private const IMAGE_URL:String = "http://www.designzzz.com/wp-content/uploads/2010/06/Flowers_3_by_PHOTOcrazy.jpg"; //------------------------------------------------------- // const //------------------------------------------------------- private const DOTS_MAX:Number = 50; // 1モーションで保持する頂点数 private const FRICTION:Number = 0.98; private const EDGE_COLOR:uint = 0x666666; // 太いラインのエッジカラー //------------------------------------------------------- // vars //------------------------------------------------------- private var _drawImage:BitmapData; private var _dotNumber:Number = 0; private var _dots:Vector.<Vertex>; private var _codeWidth:Number = 1; private var _startX:Number; private var _startY:Number; private var _layerA:Sprite; // 上のレイヤー(太いライン) private var _layerB:Sprite; // 下のレイヤー(細いライン) private var _drawTarget:Sprite; // ビットマップ描画するターゲット private var _canvas:BitmapData; // 描画先 private var _holder:Sprite; // 描画したビットマップのいれもの public function AbstractPainting() { init(); } private function init():void { var req:URLRequest = new URLRequest(IMAGE_URL); var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete); loader.load( req, new LoaderContext(true)); } private function loadComplete(e:Event):void { e.target.removeEventListener(Event.COMPLETE, loadComplete); var sw:int = stage.stageWidth; var sh:int = stage.stageHeight; _startX = sw/2; _startY = sh/2; var source:Bitmap = e.target.loader.content as Bitmap; source.width = sw; source.height = sh; _drawImage = new BitmapData(sw,sh, false, 0x000); _drawImage.draw(source); _layerA = new Sprite();// 上のレイヤー _layerB = new Sprite();// 下のレイヤー...ちょっとずらす _layerB.x = 10; _layerB.y = 10; // 上のレイヤーだけちょっと色かえる var colorTransform:ColorTransform = new ColorTransform(1,1,1,2,20,30,20,20); _layerB.transform.colorTransform = colorTransform; _drawTarget = new Sprite(); _drawTarget.addChild(_layerA); _drawTarget.addChild(_layerB); _holder = new Sprite(); _holder.x = sw/2; _holder.z = 300; addChild(_holder); _canvas = new BitmapData(sw,sh,false,0xEEEEEE); var canvasBitmap:Bitmap = new Bitmap(_canvas,"auto",true); canvasBitmap.x = -232; _holder.addChild(canvasBitmap); _dots = new Vector.<Vertex>(); var timer:Timer = new Timer(30, 0); timer.addEventListener(TimerEvent.TIMER, createDot); timer.start(); addEventListener(Event.ENTER_FRAME, enterFrameHandler); } private function randomRange( min:Number, max:Number ):Number { return min + Math.random() * (max + 1 - min); } //------------------------------------------------------- // Private Event Handler //------------------------------------------------------- private function createDot(e:TimerEvent):void { var dot:Vertex = new Vertex(); var px:Number = _startX + randomRange(-40,40); var py:Number = _startY + randomRange(-40,40); // ステージからはみ出たら適当な場所へ戻す if(px > stage.stageWidth || py > stage.stageHeight || px < 0 || py < 0) { px = Math.random() * stage.stageWidth; py = Math.random() * stage.stageHeight; dot.ajust = true; // 位置変更フラグ } _startX = px; _startY = py; dot.x = _startX; dot.y = _startY; _dots.push(dot); if (_dotNumber >= DOTS_MAX) { var target:Vertex = _dots.shift(); target = null; } _dotNumber ++; } private function enterFrameHandler(e:Event):void { _layerA.graphics.clear(); _layerB.graphics.clear(); var codeWidth:Number = 1; // layerBの線の太さ var brushThickness:Number = 4; // 線の太さ var pressure:Number = 0; // 筆圧っぽさ var l:int = _dots.length; // 一回まわして角度を計算しておく for(var i:int = l-1; i > 0; i-- ) { if( i != l-1 ) { var dot:Vertex = _dots[i]; var dotB:Vertex = _dots[i-1]; // 一つ前のポイント(基準値) var disX:Number = dotB.x - dot.x; var disY:Number = dotB.y - dot.y; // X:Yの角度から垂直になるポイントへの角度 dot.angle = Math.atan2(disX, disY) + Math.PI / 2; } } // 線の描画部分 for(var j:int = l-1; j > 0; j-- ) { dot = _dots[j]; var color:uint = _drawImage.getPixel(dot.x, dot.y); if (j>0) { brushThickness += 0.1; codeWidth += 0.01; pressure += 0.02; } else { brushThickness *= FRICTION; codeWidth *= FRICTION; pressure *= FRICTION; } if( j == l-1 ) { // はみ出たポイントを戻すタイミングで円を書く if(dot.ajust) drawCircle(dot,color); _layerA.graphics.moveTo(dot.x, dot.y); _layerB.graphics.moveTo(dot.x, dot.y); } else { dotB = _dots[j-1]; disX = dotB.x - dot.x; disY = dotB.y - dot.y; var mx:Number = dot.x + (disX)*0.4; var my:Number = dot.y + (disY)*0.4; var cosA:Number = brushThickness*Math.cos(dot.angle); var cosB:Number = brushThickness*Math.cos(dotB.angle); var sinA:Number = brushThickness*Math.sin(dot.angle); var sinB:Number = brushThickness*Math.sin(dotB.angle); // 上のレイヤー _layerB.graphics.lineStyle(codeWidth, color, pressure); _layerB.graphics.curveTo(dotB.x, dotB.y, mx, my); _layerB.graphics.lineTo(mx, my); // 下のレイヤー if(!dot.ajust) { _layerA.graphics.beginFill(color,0.4); _layerA.graphics.moveTo(mx,my); _layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0); _layerA.graphics.moveTo(dot.x + cosA, dot.y + sinA); _layerA.graphics.lineTo(dot.x - cosA, dot.y - sinA); _layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0.2); _layerA.graphics.lineTo(dotB.x - cosB, dotB.y - sinB); _layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0); _layerA.graphics.lineTo(dotB.x + cosB, dotB.y + sinB); _layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0.2); _layerA.graphics.lineTo(dot.x + cosA, dot.y + sinA); _layerA.graphics.moveTo(mx, my); } } } _canvas.draw(_drawTarget); var center:Number = stage.stageWidth/2; var p:Number = (center - mouseX)/center* -180; SimpleTween.addTween(_holder, {rotationY:p}); } private function drawCircle(target:Vertex, color:uint):void { for(var i:int = 0; i<8; i++) { var px:Number = target.x + randomRange( -100, 100 ); var py:Number = target.y + randomRange( -100, 100 ); var r:Number = Math.random()* 4; _layerA.graphics.beginFill(color,1); _layerA.graphics.drawCircle(px,py,r); } } } } import flash.display.DisplayObject; /** 頂点クラス */ class Vertex { private const GRAVITY:Number = 0.5; // 重力 private const FRICTION:Number = 0.98; // 減速抵抗 public var x:Number; public var y:Number; public var rad:Number = 2; public var color:uint; public var randonNum:Number; public var angle:Number; public var ajust:Boolean = false; private var speedX:Number; private var speedY:Number; public function Vertex() { init(); } private function init():void { var angle:Number = Math.random()*Math.PI*2; randonNum = Math.random() * 4; speedX = Math.cos(angle) * randonNum; speedY = Math.sin(angle) * randonNum; } public function upDate():void { speedX *= FRICTION; speedY *= FRICTION; x += speedX; y += speedY; } } /** TWEEN用 あとで使うかも。いまのとこ一回しか使ってない。 */ class SimpleTween { private static const EASE_VALUE:Number = 0.2; public static function addTween( target:Object, obj:Object ):void { for(var istr:String in obj) { var a:Number = target[istr]; var b:Number = obj[istr]; target[istr] = a + (b-a) * EASE_VALUE; } } } Code Fullscreen Preview Fullscreen target color rotationY mouseX addEventListener Math.min Math.cos shift TimerEvent.ENTER_FRAME TimerEvent Object Timer start TimerEvent.TIMER Math.max Math.sin Math.atan2 Math.PI push length