package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.DisplayObject; import flash.display.Graphics; import flash.display.Loader; import flash.display.LoaderInfo; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageQuality; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.MouseEvent; import flash.filters.BitmapFilter; import flash.filters.DisplacementMapFilter; import flash.geom.Point; import flash.net.FileFilter; import flash.net.FileReference; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.utils.ByteArray; import com.flashdynamix.utils.SWFProfiler; [SWF(width=465, height=465, frameRate=30, backgroundColor=0xffffff)] public class Main extends Sprite { private var _fileRef:FileReference; private var _fileFilters:Array = [new FileFilter("Images", "*.jpg;*.png;")]; private var _currentImage:DisplayObject; private var _imageFilter:DisplacementMapFilter; private var _imageFilterMap:BitmapData; private var _imageFilterOffset:Array; public function Main() { addEventListener(Event.ADDED_TO_STAGE, initialize); } private function initialize(evt:Event):void { removeEventListener(Event.ADDED_TO_STAGE, initialize); // setup stage. stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.HIGH; stage.scaleMode = StageScaleMode.NO_SCALE; // setup debugger. SWFProfiler.init(this); createUI(); createFilter(); addEventListener(Event.ENTER_FRAME, enterFrameHandler); } private function createFilter():void { //_imageFilterMap = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xffffff); _imageFilterMap = new BitmapData(600, 600, false, 0xffffff); _imageFilter = new DisplacementMapFilter(_imageFilterMap, new Point(), 2, 2, 0, 0, "wrap"); _imageFilterOffset = [new Point()]; } private function createUI():void { var ui:Sprite, sp:Sprite, g:Graphics, txt:TextField, fmt:TextFormat, i:uint, pos:Number, labelList:Array, callbackList:Array; // ui container. ui = addChild(new AutoHide()) as Sprite; fmt = new TextFormat("Arial", 12); fmt.leftMargin = fmt.rightMargin = 5; labelList = [ "upload", "save", ]; callbackList = [ uploadClickHandler, saveClickHandler, ]; pos = 10; while (labelList.length) { txt = new TextField(); txt.autoSize = TextFieldAutoSize.LEFT; txt.defaultTextFormat = fmt; txt.selectable = false; txt.text = labelList.shift(); sp = new Sprite(); sp.x = pos; sp.y = 10; sp.mouseChildren = false; sp.buttonMode = true; sp.blendMode = BlendMode.INVERT; sp.addEventListener(MouseEvent.CLICK, callbackList.shift()); g = sp.graphics; g.lineStyle(1, 0x666666); g.beginFill(0xd8d8d8, 0); g.drawRect(0, 0, txt.width, txt.height); g.endFill(); sp.addChild(txt); ui.addChild(sp); pos = sp.y + sp.width + 10; } } private function enterFrameHandler(evt:Event):void { if (!_currentImage) return; _imageFilterOffset[0].y -= 3; _imageFilterMap.perlinNoise(stage.stageWidth >> 1, stage.stageHeight >> 1, 1, 5, true, true, 7, true, _imageFilterOffset); _imageFilter.scaleX += 1; _imageFilter.scaleY += 1; _currentImage.filters = [_imageFilter]; } private function saveClickHandler(evt:MouseEvent):void { var data:BitmapData, png:ByteArray, file:FileReference; if (!_currentImage) return; data = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0); data.draw(_currentImage, _currentImage.transform.matrix); png = PNGEnc.encode(data); file = new FileReference(); file.save(png, 'hoge.png'); } private function uploadClickHandler(evt:MouseEvent):void { _fileRef = new FileReference(); _fileRef.addEventListener(Event.SELECT, uploadSelectHandler); _fileRef.browse(_fileFilters); } private function uploadSelectHandler(evt:Event):void { _fileRef.removeEventListener(Event.SELECT, uploadSelectHandler); _fileRef.addEventListener(Event.COMPLETE, uploadCompleteHandler); _fileRef.load(); } private function uploadCompleteHandler(evt:Event):void { var loader:Loader; _fileRef.removeEventListener(Event.COMPLETE, uploadCompleteHandler); loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler); loader.loadBytes(_fileRef.data); _fileRef = null; } private function loaderCompleteHandler(evt:Event):void { var info:LoaderInfo, loader:Loader, //bm:Bitmap, //data:BitmapData, scale:Number; info = LoaderInfo(evt.target); info.removeEventListener(Event.COMPLETE, loaderCompleteHandler); loader = info.loader; scale = Math.max(stage.stageWidth / loader.width, stage.stageHeight / loader.height); loader.scaleX = loader.scaleY = scale; loader.x -= (loader.width - stage.stageWidth) >> 1; loader.y -= (loader.height - stage.stageHeight) >> 1; //data = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0); //data.draw(loader, loader.transform.matrix); //bm = new Bitmap(data); //bm.smoothing = true; if (_currentImage) removeChild(_currentImage); _currentImage = addChildAt(loader, 0); } } } import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.geom.Rectangle; import flash.utils.ByteArray; import flash.utils.Timer; class AutoHide extends Sprite { private var _timer:Timer; public function AutoHide() { _timer = new Timer(3000, 1); addEventListener(Event.ADDED_TO_STAGE, initialize); } private function initialize(evt:Event):void { removeEventListener(Event.ADDED_TO_STAGE, initialize); stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); _timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler); _timer.start(); } private function timerCompleteHandler(evt:TimerEvent):void { visible = false; } private function mouseMoveHandler(evt:MouseEvent):void { visible = true; _timer.reset(); _timer.start(); } } // http://www.5etdemi.com/blog/archives/2006/12/as3-png-encoder-faster-better/ // @see Saqoosha http://wonderfl.net/code/21cfc87e11ffb354562c393a6e55666d61e15bf6 class PNGEnc { public static function encode(img:BitmapData, type:uint = 0):ByteArray { // Create output byte array var png:ByteArray = new ByteArray(); // Write PNG signature png.writeUnsignedInt(0x89504e47); png.writeUnsignedInt(0x0D0A1A0A); // Build IHDR chunk var IHDR:ByteArray = new ByteArray(); IHDR.writeInt(img.width); IHDR.writeInt(img.height); if(img.transparent || type == 0) { IHDR.writeUnsignedInt(0x08060000); // 32bit RGBA } else { IHDR.writeUnsignedInt(0x08020000); //24bit RGB } IHDR.writeByte(0); writeChunk(png,0x49484452,IHDR); // Build IDAT chunk var IDAT:ByteArray= new ByteArray(); switch(type) { case 0: writeRaw(img, IDAT); break; case 1: writeSub(img, IDAT); break; } IDAT.compress(); writeChunk(png,0x49444154,IDAT); // Build IEND chunk writeChunk(png,0x49454E44,null); // return PNG return png; } private static function writeRaw(img:BitmapData, IDAT:ByteArray):void { var h:int = img.height; var w:int = img.width; var transparent:Boolean = img.transparent; for(var i:int=0;i < h;i++) { // no filter if ( !transparent ) { var subImage:ByteArray = img.getPixels( new Rectangle(0, i, w, 1)); //Here we overwrite the alpha value of the first pixel //to be the filter 0 flag subImage[0] = 0; IDAT.writeBytes(subImage); //And we add a byte at the end to wrap the alpha values IDAT.writeByte(0xff); } else { IDAT.writeByte(0); var p:uint; for(var j:int=0;j < w;j++) { p = img.getPixel32(j,i); IDAT.writeUnsignedInt( uint(((p&0xFFFFFF) << 8)| (p>>>24))); } } } } private static function writeSub(img:BitmapData, IDAT:ByteArray):void { var r1:uint; var g1:uint; var b1:uint; var a1:uint; var r2:uint; var g2:uint; var b2:uint; var a2:uint; var r3:uint; var g3:uint; var b3:uint; var a3:uint; var p:uint; var h:int = img.height; var w:int = img.width; for(var i:int=0;i < h;i++) { // no filter IDAT.writeByte(1); if ( !img.transparent ) { r1 = 0; g1 = 0; b1 = 0; a1 = 0xff; for(var j:int=0;j < w;j++) { p = img.getPixel(j,i); r2 = p >> 16 & 0xff; g2 = p >> 8 & 0xff; b2 = p & 0xff; r3 = (r2 - r1 + 256) & 0xff; g3 = (g2 - g1 + 256) & 0xff; b3 = (b2 - b1 + 256) & 0xff; IDAT.writeByte(r3); IDAT.writeByte(g3); IDAT.writeByte(b3); r1 = r2; g1 = g2; b1 = b2; a1 = 0; } } else { r1 = 0; g1 = 0; b1 = 0; a1 = 0; for(j=0;j < w;j++) { p = img.getPixel32(j,i); a2 = p >> 24 & 0xff; r2 = p >> 16 & 0xff; g2 = p >> 8 & 0xff; b2 = p & 0xff; r3 = (r2 - r1 + 256) & 0xff; g3 = (g2 - g1 + 256) & 0xff; b3 = (b2 - b1 + 256) & 0xff; a3 = (a2 - a1 + 256) & 0xff; IDAT.writeByte(r3); IDAT.writeByte(g3); IDAT.writeByte(b3); IDAT.writeByte(a3); r1 = r2; g1 = g2; b1 = b2; a1 = a2; } } } } private static var crcTable:Array; private static var crcTableComputed:Boolean = false; private static function writeChunk(png:ByteArray, type:uint, data:ByteArray):void { var c:uint; if (!crcTableComputed) { crcTableComputed = true; crcTable = []; for (var n:uint = 0; n < 256; n++) { c = n; for (var k:uint = 0; k < 8; k++) { if (c & 1) { c = uint(uint(0xedb88320) ^ uint(c >>> 1)); } else { c = uint(c >>> 1); } } crcTable[n] = c; } } var len:uint = 0; if (data != null) { len = data.length; } png.writeUnsignedInt(len); var p:uint = png.position; png.writeUnsignedInt(type); if ( data != null ) { png.writeBytes(data); } var e:uint = png.position; png.position = p; c = 0xffffffff; for (var i:int = 0; i < (e-p); i++) { c = uint(crcTable[ (c ^ png.readUnsignedByte()) & 0xff] ^ (c >>> 8)); } c = uint(c^uint(0xffffffff)); png.position = e; png.writeUnsignedInt(c); } } flash on 2009-10-24