package { import flash.display.*; import flash.filters.*; import flash.geom.*; import flash.events.*; [SWF(width='416',height='296',backgroundColor='0x333333',frameRate='255')] public class ImageResizing extends Sprite { [Embed(source='/assets/pic.jpg')] private static const PICTURE: Class; private static const origin: Point = new Point; private static const colorMatrix: ColorMatrixFilter = new ColorMatrixFilter( new Array( .2125, .7154, .0721, 0, 0, .2125, .7154, .0721, 0, 0, .2125, .7154, .0721, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) ); private static const convolution: ConvolutionFilter = new ConvolutionFilter( 3, 3, new Array( 0, -1, 0, -1, 4, -1, 0, -1, 0 ) ); private var screen: BitmapData; private var bitmapData: BitmapData; private var mode: Boolean; public function ImageResizing() { stage.scaleMode = StageScaleMode.NO_SCALE; screen = new BitmapData( stage.stageWidth, stage.stageHeight, false, 0 ); bitmapData = Bitmap( new PICTURE ).bitmapData; addChild( new Bitmap( screen ) ); stage.addEventListener( KeyboardEvent.KEY_UP, onKeyUp ); stage.addEventListener( MouseEvent.CLICK, onClick ); stage.addEventListener( Event.ENTER_FRAME, onEnterFrame ); } private function onClick( event: MouseEvent ): void { bitmapData = Bitmap( new PICTURE ).bitmapData; } private function onKeyUp( event: KeyboardEvent ): void { mode = !mode; } private function onEnterFrame( event: Event ): void { screen.fillRect( screen.rect, 0 ); bitmapData = ( mode ) ? stepX( bitmapData ) : stepY( bitmapData ); screen.draw( bitmapData ); } private function stepX( input: BitmapData ): BitmapData { if ( input.width == 1 ) return input; var energyMap: BitmapData = input.clone(); energyMap.applyFilter( energyMap, energyMap.rect, origin, colorMatrix ); energyMap.applyFilter( energyMap, energyMap.rect, origin, convolution ); var seamsV: Array = new Array( energyMap.width ); var seam: Seam; var n: int = energyMap.width; for ( var x: int = 0; x < n; ++x ) { seam = new Seam; seam.direction = SeamDirection.V; seam.start = x; seam.bake( bitmapData ); seamsV.push( seam ); } seamsV.sortOn( 'energy' ); n = input.width - 1; var shift: int = 0; var output: BitmapData = new BitmapData( n, input.height, input.transparent, 0 ); var p: SeamPoint = Seam( seamsV[ 0 ] ).points; for ( var y: int = 0; y < input.height; y++ ) { for ( x = 0; x < input.width; x++ ) { if ( x == p.x ) { shift = 1; } else { output.setPixel( x - shift, y, input.getPixel( x, y ) ); } } p = p.next; shift = 0; } return output; } private function stepY( input: BitmapData ): BitmapData { if ( input.height == 1 ) return input; var energyMap: BitmapData = input.clone(); energyMap.applyFilter( energyMap, energyMap.rect, origin, colorMatrix ); energyMap.applyFilter( energyMap, energyMap.rect, origin, convolution ); var n: int = energyMap.height; var seamsV: Array = new Array( n ); var seam: Seam; var x: int, y: int; for ( y = 0; y < n; ++y ) { seam = new Seam; seam.direction = SeamDirection.H; seam.start = y; seam.bake( bitmapData ); seamsV.push( seam ); } seamsV.sortOn( 'energy' ); var shift: int = 0; var output: BitmapData = new BitmapData( input.width, input.height - 1, input.transparent, 0 ); var p: SeamPoint = Seam( seamsV[ 0 ] ).points; var w: int = input.width; var h: int = input.height; for ( x = 0; x < w; x++ ) { for ( y = 0; y < h; y++ ) { if ( y == p.y ) { shift = 1; } else { output.setPixel( x, y - shift, input.getPixel( x, y ) ); } } p = p.next; shift = 0; } return output; } private function renderSeam( x: int, y: int ): void { screen.setPixel( x, y, 0xff0000 ); } } } import flash.display.BitmapData; class SeamDirection { public static const V: int = 0; public static const H: int = 1; } class Seam { protected var _start: int; protected var _direction: int; protected var _points: SeamPoint; protected var _energy: Number; public function Seam() {} public function set start( value: int ): void { _start = value; _points = new SeamPoint; if ( _direction == SeamDirection.H ) { _points.x = 0; _points.y = _start; } else { _points.x = _start; _points.y = 0; } } public function get points(): SeamPoint { return _points; } public function set direction( value: int ): void { _direction = value; } public function get energy(): Number { return _energy; } public function bake( energyMap: BitmapData ): void { var point: SeamPoint = _points; var o: int = _start; var isV: Boolean = ( _direction == SeamDirection.V ); var end: int = ( isV ) ? energyMap.height : energyMap.width; var endO: int = ( isV ) ? energyMap.width : energyMap.height; var differenceTotal: uint; var energy: int; var e0: int, e1: int, e2: int; var d0: int, d1: int, d2: int; var min: int; for ( var p: int = 1; p < end; p++ ) { point = point.next = new SeamPoint; if ( isV ) { energy = energyMap.getPixel( o, p - 1 ) & 0xff; e0 = energyMap.getPixel( o - 1, p ) & 0xff; e1 = energyMap.getPixel( o , p ) & 0xff; e2 = energyMap.getPixel( o + 1, p ) & 0xff; d0 = Math.abs( energy - e0 ); d1 = Math.abs( energy - e1 ); d2 = Math.abs( energy - e2 ); min = Math.min( d0, d1, d2 ); if ( min == d0 ) o--; else if ( min == d2 ) o++; if ( o < 0 ) o = 0; if ( o == endO ) o = endO - 1; point.x = o; point.y = p; } else { energy = energyMap.getPixel( p - 1, o ) & 0xff; e0 = energyMap.getPixel( p, o - 1) & 0xff; e1 = energyMap.getPixel( p, o ) & 0xff; e2 = energyMap.getPixel( p, o + 1) & 0xff; d0 = Math.abs( energy - e0 ); d1 = Math.abs( energy - e1 ); d2 = Math.abs( energy - e2 ); min = Math.min( d0, d1, d2 ); if ( min == d0 ) o--; else if ( min == d2 ) o++; if ( o < 0 ) o = 0; if ( o == endO ) o = endO - 1; point.x = p; point.y = o; } differenceTotal += min; } _energy = ( differenceTotal / end ) / 255; } public function walk( func: Function ): void { var p: SeamPoint = _points; while ( p ) { func( p.x, p.y ); p = p.next; } } } class SeamPoint { public var x: int; public var y: int; public var next: SeamPoint; }