/* SeamCarvingApp.as (goes with SeamCarving.as) Lee Felarca http://www.zeropointnine.com/blog 9-1-2007 v0.8 Source code licensed under a Creative Commons Attribution 3.0 License. http://creativecommons.org/licenses/by/3.0/ Some Rights Reserved. */ package { import flash.display.*; import flash.events.*; import flash.text.*; import flash.filters.GlowFilter; [SWF(width="600",height="500", backgroundColor="#AAAAAA")] public class SeamCarvingApp extends Sprite { [Embed(source="landscape.jpg")] private var clsImageA:Class; [Embed(source="english_seaside.jpg")] private var clsImageB:Class; [Embed(source="italyd.jpg")] private var clsImageC:Class; [Embed(source="stillife.jpg")] private var clsImageD:Class; private const IMAGES:Array = [new clsImageC, new clsImageA, new clsImageB, new clsImageD]; private var imageAt:int = 0; private var sprImage:Sprite = new Sprite(); private var sprSeam:Sprite = new Sprite(); private var bmdShrink:Array; private var bmdExpand:Array; private var seams:Array; private var bmdGradMag:BitmapData; private var bmdMagViz:BitmapData; private var bmdSeamViz:BitmapData; private var bmdAt:int = 0; private var counter:int = 0; private var dragStartY:int = 0; private var dragStartBmdNum:int = 0; private var tf1:TextField = new TextField(); private var tf2:TextField = new TextField(); private var tf3:TextField = new TextField(); public function SeamCarvingApp() { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; this.addChild(sprImage); this.addChild(sprSeam); this.addChild(tf1); this.addChild(tf2); this.addChild(tf3); sprSeam.filters = [ new GlowFilter(0x0, 0.7, 1,2,2) ]; initImage(); this.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false,0,true); sprImage.addEventListener(MouseEvent.MOUSE_DOWN, onDragStart, false,0,true); this.addEventListener(Event.ENTER_FRAME, loop, false,0,true); } private function initImage():void { bmdShrink = new Array(); bmdExpand = new Array(); seams = new Array(); bmdAt = 0; counter = 25; var b:Bitmap = IMAGES[imageAt]; bmdShrink[0] = new BitmapData(b.width, b.height); bmdShrink[0].draw(b); bmdExpand[0] = new BitmapData(b.width, b.height); bmdExpand[0].draw(b); seams[0] = null; tf1.width = stage.stageWidth; tf1.defaultTextFormat = new TextFormat("Arial",11,null,true,null,null,null,null,"center"); tf1.text = "Thinking... Please wait a while..."; tf2.width = stage.stageWidth; tf2.defaultTextFormat = new TextFormat("Arial",10,null,null,null,null,null,null,"center"); tf3.width = stage.stageWidth; tf3.defaultTextFormat = new TextFormat("Arial",10,null,null,null,null,null,null,"center"); tf3.text = "[SPACE] Cycle through images [M] Calculate more seams [X] Cancel calculations"; tf3.y = stage.stageHeight - 23; updateBitmaps(); } private function onDragStart(e:MouseEvent):void { if (counter > 0) return; dragStartY = this.mouseY; dragStartBmdNum = bmdAt; this.addEventListener(MouseEvent.MOUSE_UP, onDragEnd, false,0,true); this.addEventListener(MouseEvent.MOUSE_MOVE, onDrag, false,0,true); } private function onDrag(e:MouseEvent):void { var d:int = dragStartY - this.mouseY; bmdAt = dragStartBmdNum + d; if (bmdAt > bmdShrink.length - 1) bmdAt = bmdShrink.length - 1; if (bmdAt < -bmdShrink.length + 1) bmdAt = -bmdShrink.length + 1; drawDisplay(); } private function onDragEnd(e:MouseEvent):void { this.removeEventListener(MouseEvent.MOUSE_UP, onDragEnd); this.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag); } private function loop(e:Event):void { stage.focus = this; if (counter>0) { counter--; doAll(); return; } } private function doAll():void { var idxNew:int = bmdShrink.length; var idxLast:int = idxNew - 1; seams[idxNew] = SeamCarving.getMinSeam(bmdGradMag); var newBmd1:BitmapData = SeamCarving.shrinkImage( bmdShrink[idxLast], seams[idxNew] ) bmdShrink[idxNew] = newBmd1; var newBmd2:BitmapData = SeamCarving.expandImage( bmdExpand[idxLast], seams[idxNew] ) bmdExpand[idxNew] = newBmd2; bmdAt = idxNew; updateBitmaps(); } private function onKeyDown(e:KeyboardEvent):void { if (e.charCode==32) { // space imageAt++; if (imageAt > IMAGES.length-1) imageAt = 0; initImage(); } else if (e.charCode==109) { // m if (bmdShrink.length + counter + 50 + 25 <= bmdShrink[0].height) counter += 25; } else if (e.charCode==120) { // x counter = 0; drawDisplay(); } } private function makeGradMagViz($b:BitmapData) : BitmapData { // Return a 'visually-readable' version of the gradient magnitude map var b:BitmapData = new BitmapData($b.width, $b.height); var col:Number; for (var y:int = 0; y < $b.height; y++) { for (var x:int = 0; x < $b.width; x++) { col = $b.getPixel(x,y); col = Math.sqrt(col); col = Math.min(col,100); // range 0-100 var c:uint = int(col*2.55); // range 0-255 b.setPixel( x,y, c ) // blue-scale } } return b } private function makeSeamViz($a:Array) : BitmapData { // Return a bitmapdata representing the seam array var b:BitmapData = new BitmapData( bmdShrink[bmdAt].width, bmdShrink[bmdAt].height, true, 0x00000000); for (var i:int = 0; i < $a.length; i++) { b.setPixel32( $a[i].x, $a[i].y, 0xFFFFFFFF); } return b; } private function updateBitmaps():void { bmdGradMag = SeamCarving.makeGradientMagnitudeMap(bmdShrink[ bmdShrink.length-1 ]); if (seams[Math.abs(bmdAt)]) bmdSeamViz = makeSeamViz( seams[Math.abs(bmdAt)] ); drawDisplay(); } private function drawDisplay():void { var b:BitmapData; if (bmdAt >= 0) b = bmdShrink[bmdAt]; else b = bmdExpand[bmdAt*-1]; sprImage.graphics.clear(); sprImage.graphics.beginBitmapFill(b); sprImage.graphics.drawRect(0,0,b.width, b.height); sprImage.graphics.endFill(); sprImage.x = int((stage.stageWidth - sprImage.width) / 2); sprImage.y = int((stage.stageHeight - sprImage.height) / 2) - 20; sprSeam.graphics.clear(); if (bmdSeamViz && counter > 0) { sprSeam.graphics.clear(); sprSeam.graphics.beginBitmapFill(bmdSeamViz); sprSeam.graphics.drawRect(0,0,bmdSeamViz.width, bmdSeamViz.height); sprSeam.graphics.endFill(); sprSeam.x = sprImage.x; sprSeam.y = sprImage.y; } tf1.y = sprImage.y + sprImage.height + 10; tf2.y = tf1.y + 23; if (counter==0) { tf1.text = "Click and drag to vertically resize image"; sprImage.buttonMode = true; } else { tf1.text = "Thinking. Please wait a while. (Calculating " + counter + " more seams)"; sprImage.buttonMode = false; } tf2.text = "Current height:" + b.height + "; Original height:" + bmdShrink[0].height; } } // class } // package