/* * 矩形選択ツールをもうちょっと使いやすく。 * * 矩形を描いた後にドラッグやカーソルキーで * 変形できる。 * * 矩形選択ツールの部分以外は最低限の機能。 * * 参考 * http://iccii.seesaa.net/article/28058268.html * */ package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Matrix; import flash.text.TextField; import flash.text.TextFormat; import com.bit101.components.PushButton; /** * ... * @author umhr */ [SWF(backgroundColor="0x777777")] public class Main extends Sprite { private var _highlite:Highlite; private var _canvas:Sprite; private var _bitmap:Bitmap; public function Main():void { stage.scaleMode = "noScale"; stage.align = "TL"; _canvas = new Sprite(); this.addChild(_canvas); new PushButton(this,0,0,"LOAD IMG",atLoad); new PushButton(this,stage.stageWidth-100,0,"SAVE PNG",atSave); } private function atLoad(event:MouseEvent):void{ var loadFile:LoadFile = new LoadFile(); loadFile.atComplete = atComplete; loadFile.Start(); } private function atComplete(event:Event):void { while (_canvas.numChildren > 0) { _canvas.removeChildAt(0); } //読み込んだ画像を中央に置く _bitmap = event.target.content; _bitmap.x = Math.floor((stage.stageWidth - _bitmap.width) / 2); _bitmap.y = Math.floor((stage.stageHeight - _bitmap.height) / 2); _canvas.addChild(_bitmap); //矩形選択ツール _highlite = new Highlite(_bitmap.x, _bitmap.y, _bitmap.width, _bitmap.height); _canvas.addChild(_highlite); } //画像の書き出しとりあえずPNG固定 private function atSave(event:MouseEvent):void { if (_canvas.numChildren == 0 || _highlite.selectedRectangle.width*_highlite.selectedRectangle.height == 0) { return }; var bitmapData:BitmapData = new BitmapData(_highlite.selectedRectangle.width,_highlite.selectedRectangle.height,true,0); bitmapData.draw(_bitmap, new Matrix(1, 0, 0, 1, -_highlite.selectedRectangle.x, -_highlite.selectedRectangle.y)); SaveImage.PNGfromDisplayObject(new Bitmap(bitmapData)); } } } import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.utils.Dictionary; class Highlite extends Sprite { private var _in:Point; private var _rectangle:Rectangle; public var selectedRectangle:Rectangle; private var _selectedArea:SelectedArea; public var onChange:Function = function(selectedRectangle:Rectangle):void{}; public function Highlite(x:Number=0,y:Number=0,width:Number=0,height:Number=0){ _in = new Point(); rectangle = new Rectangle(x, y, width, height); selectedRectangle = new Rectangle(); _selectedArea = new SelectedArea(); this.addChild(_selectedArea); this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); this.addEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage); } private function onAddedToStage(event:Event):void { this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown); stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove); stage.addEventListener(MouseEvent.MOUSE_UP, onUp); stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); } private function onRemoveFromStage(event:Event):void { this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); this.removeEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage); stage.removeEventListener(MouseEvent.MOUSE_DOWN, onDown); stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove); stage.removeEventListener(MouseEvent.MOUSE_UP, onUp); stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); } //矢印キーで選択域を移動できる。 private function onKeyDown(event:KeyboardEvent):void { if (_selectedArea.selected < 0) { return }; var keyObj:Object = { 37:[ -1, 0], 38:[0, -1], 39:[1, 0], 40:[0, 1] }; if (keyObj[event.keyCode]) { //if (!isNaN(_selectedArea.dictionary[stage.focus]) && _selectedArea.dictionary[stage.focus] < 9) { //var selected:int = _selectedArea.dictionary[stage.focus]; if (_selectedArea.selected < 9) { var selected:int = _selectedArea.selected; var pointTL:Point = selectedRectangle.topLeft; var pointBR:Point = selectedRectangle.bottomRight; if (selected == 4) { pointTL.x += keyObj[event.keyCode][0]; pointBR.x += keyObj[event.keyCode][0]; }else if(selected%3 == 0){ pointTL.x += keyObj[event.keyCode][0]; }else if(selected%3 == 2){ pointBR.x += keyObj[event.keyCode][0]; } if (selected == 4) { pointTL.y += keyObj[event.keyCode][1]; pointBR.y += keyObj[event.keyCode][1]; }else if(selected <= 2){ pointTL.y += keyObj[event.keyCode][1]; }else if(selected >= 6){ pointBR.y += keyObj[event.keyCode][1]; } target(pointTL, pointBR); } } //trace(event.keyCode, stage.focus, _selectedArea.dictionary[stage.focus],keyObj[event.keyCode]) } private function target(a:Point, b:Point):void { var x:Number = Math.max(0, Math.min(a.x, b.x)); var y:Number = Math.max(0, Math.min(a.y, b.y)); var w:Number = Math.min(rectangle.width, Math.max(a.x, b.x)) - x; var h:Number = Math.min(rectangle.height, Math.max(a.y, b.y)) - y; if (w < 0 || h < 0) { return }; this.graphics.clear(); this.graphics.beginFill(0xCC3333,0.5); this.graphics.drawRect(0, 0, rectangle.width, rectangle.height); this.graphics.drawRect(x, y, w, h); _selectedArea.setSize(x, y, w, h); this.graphics.endFill(); selectedRectangle = new Rectangle(x, y, w, h); onChange(selectedRectangle); } public function set rectangle(rect:Rectangle):void{ this.x = rect.x; this.y = rect.y; _rectangle = rect; } public function get rectangle():Rectangle{ return _rectangle; } private var _isUp:Boolean; private function onUp(event:MouseEvent):void { _isUp = true; } private function onDown(event:MouseEvent):void { if (_selectedArea.dictionary[event.target] == undefined || !_isUp) { _isUp = false; _in = new Point(this.mouseX, this.mouseY); _selectedArea.selected = -1; }else if (!isNaN(_selectedArea.dictionary[event.target])) { _selectedArea.handlePoint = new Point(this.mouseX, this.mouseY); _selectedArea.selected = _selectedArea.dictionary[event.target]; } } //マウスドラッグ時 private function onMove(event:MouseEvent):void { _selectedArea.isMouseOver = selectedRectangle.contains(this.mouseX, this.mouseY); if (!event.buttonDown) { return }; if (_selectedArea.dictionary[event.target] == undefined && !_isUp) { //選択域を作る target(_in, new Point(this.mouseX, this.mouseY)); }else if (_selectedArea.selected > -1) { //選択域をドラッグする var selected:int = _selectedArea.selected; if (selected == 100) { return }; var subtract:Point = _selectedArea.handlePoint.subtract(new Point(this.mouseX, this.mouseY)); var pointTL:Point = selectedRectangle.topLeft; var pointBR:Point = selectedRectangle.bottomRight; if (selected == 4) { pointTL.x -= subtract.x; pointBR.x -= subtract.x; }else if(selected%3 == 0){ pointTL.x -= subtract.x; }else if(selected%3 == 2){ pointBR.x -= subtract.x; } if (selected == 4) { pointTL.y -= subtract.y; pointBR.y -= subtract.y; }else if(selected <= 2){ pointTL.y -= subtract.y; }else if(selected >= 6){ pointBR.y -= subtract.y; } target(pointTL, pointBR); _selectedArea.handlePoint = new Point(this.mouseX, this.mouseY); } } } class SelectedArea extends Sprite { public var handlePoint:Point; public var selected:int; private var _handles:Array; public var dictionary:Dictionary; private var _handleWidth:int; private var _handleHeight:int; private var _isMouseOver:Boolean; public function SelectedArea() { super(); dictionary = new Dictionary(); dictionary[this] = 100; handlePoint = new Point(); selected = -1; _handles = []; for (var i:int = 0; i < 9; i++) { _handles[i] = new Sprite(); this.addChild(_handles[i]); dictionary[_handles[i]] = i; } } //ハンドルを設置 private function setHandleGraphics(width:int, height:int):void { if ((_handleWidth == width && _handleHeight == height) && _isMouseOver) { return; } for (var i:int = 0; i < 9; i++) { _handles[i].graphics.clear(); _handles[i].graphics.beginFill(0xCCCCCC, 0); _handles[i].graphics.drawRect(0,0,width,height); _handles[i].graphics.endFill(); _handles[i].graphics.lineStyle(1, 0x666666); if(i == 0){ _handles[i].graphics.moveTo(0, height); _handles[i].graphics.lineTo(width, height); _handles[i].graphics.lineTo(width, 0); }else if(i == 1){ _handles[i].graphics.moveTo(0, 0); _handles[i].graphics.lineTo(0, height); _handles[i].graphics.lineTo(width, height); _handles[i].graphics.lineTo(width, 0); }else if(i == 2){ _handles[i].graphics.moveTo(0, 0); _handles[i].graphics.lineTo(0, height); _handles[i].graphics.lineTo(width, height); }else if(i == 3){ _handles[i].graphics.moveTo(0,0); _handles[i].graphics.lineTo(width, 0); _handles[i].graphics.lineTo(width, height); _handles[i].graphics.lineTo(0,height); }else if(i == 4){ _handles[i].graphics.moveTo(0,0); _handles[i].graphics.lineTo(0, height); _handles[i].graphics.lineTo(width, height); _handles[i].graphics.lineTo(width, 0); _handles[i].graphics.lineTo(0, 0); }else if(i == 5){ _handles[i].graphics.moveTo(width, height); _handles[i].graphics.lineTo(0,height); _handles[i].graphics.lineTo(0, 0); _handles[i].graphics.lineTo(width,0); }else if(i == 6){ _handles[i].graphics.moveTo(0, 0); _handles[i].graphics.lineTo(width,0); _handles[i].graphics.lineTo(width, height); }else if(i == 7){ _handles[i].graphics.moveTo(0, height); _handles[i].graphics.lineTo(0, 0); _handles[i].graphics.lineTo(width,0); _handles[i].graphics.lineTo(width, height); }else if(i == 8){ _handles[i].graphics.moveTo(0, height); _handles[i].graphics.lineTo(0, 0); _handles[i].graphics.lineTo(width,0); } } _handleWidth = width; _handleHeight = height; } //マウスオーバー時ハンドル表示 public function set isMouseOver(isOver:Boolean):void { if (_isMouseOver == isOver) { if (isOver || _handleWidth*_handleHeight == 0) { return; } }; if (isOver) { setHandleGraphics(_handleWidth, _handleHeight); }else { for (var i:int = 0; i < 9; i++) { _handles[i].graphics.clear(); } } _isMouseOver = isOver; } //ハンドルの位置を調整 public function setSize(x:int, y:int, width:int, height:int):void { this.x = x; this.y = y; //透明のエリアがあることによって、選択域の中のハンドルがない部分があることを検地させる this.graphics.clear(); this.graphics.beginFill(0x000000,0); this.graphics.drawRect(0, 0, width, height); this.graphics.endFill(); var w:int = Math.floor(Math.min(width / 4, 20)); var h:int = Math.floor(Math.min(height / 4, 20)); setHandleGraphics(w, h); _handles[1].x = (width - _handles[1].width) / 2; _handles[2].x = width - _handles[2].width+1; _handles[3].y = (height - _handles[3].height) / 2; _handles[4].x = (width - _handles[4].width) / 2; _handles[4].y = (height - _handles[4].height) / 2; _handles[5].x = width - _handles[5].width+1; _handles[5].y = (height - _handles[5].height) / 2; _handles[6].y = (height - _handles[6].height)+1; _handles[7].x = (width - _handles[7].width) / 2; _handles[7].y = (height - _handles[7].height) +1; _handles[8].x = width - _handles[8].width+1; _handles[8].y = (height - _handles[8].height)+1; } } import flash.display.Loader; import flash.events.Event; import flash.net.FileReference; import flash.system.LoaderContext; class LoadFile{ private var _fileReference:FileReference; public var atComplete:Function = function(event:Event):void{}; /** * 開始 * */ public function Start():void { if(_fileReference){ return; } _fileReference = new FileReference(); _fileReference.browse(); _fileReference.addEventListener(Event.SELECT,atSelect); } /** * ファイルの選択が完了すると動く * @param event * */ private function atSelect(event:Event):void{ _fileReference.removeEventListener(Event.SELECT,atSelect); _fileReference.addEventListener(Event.COMPLETE,atFileComplete); _fileReference.load(); } /** * 選択したファイルを読み込み完了すると動く * @param event * */ private function atFileComplete(event:Event):void{ _fileReference.removeEventListener(Event.COMPLETE,atFileComplete); var loader:Loader = new Loader(); loader.loadBytes(event.target.data,new LoaderContext()); loader.contentLoaderInfo.addEventListener(Event.COMPLETE,atBytesComplete); } /** * 読み込んだファイルのバイトアレイを変換完了で動く * @param event * */ private function atBytesComplete(event:Event):void{ event.target.removeEventListener(Event.COMPLETE,atBytesComplete); atComplete(event); } } import com.adobe.images.JPGEncoder; import com.adobe.images.PNGEncoder; import flash.display.BitmapData; import flash.display.DisplayObject; import flash.geom.Matrix; import flash.net.FileReference; import flash.utils.ByteArray; class SaveImage{ public function SaveImage(){}; /** * PNG画像を書き出すためのメソッド * @param displayObject * @param is32BitColor//アルファチャンネル付きか否か * @param isClearEdge//1pxの余白を付けるか否か * @param isEven//画像の大きさ(縦横)を偶数にするか否か * */ public static function PNGfromDisplayObject(displayObject:DisplayObject,is32BitColor:Boolean = true,isClearEdge:Boolean=false,isEven:Boolean=false):void{ var width:int = displayObject.width+(isClearEdge?2:0); var height:int = displayObject.height+(isClearEdge?2:0); var txty:int = isClearEdge?1:0; if(isEven){ width += width%2; height += height%2; } var bitmapData:BitmapData = new BitmapData(width,height,is32BitColor,0xFFFFFF); bitmapData.draw(displayObject,new Matrix(1,0,0,1,txty,txty)); var byteArray:ByteArray = PNGEncoder.encode(bitmapData); var fileReference:FileReference = new FileReference(); fileReference.save(byteArray,"image.png"); } /** * JPG画像を書き出すためのメソッド * @param displayObject * @param quality//画質0-100 * */ public static function JPGfromDisplayObject(displayObject:DisplayObject,quality:Number=50):void{ var width:int = displayObject.width; var height:int = displayObject.height; var bitmapData:BitmapData = new BitmapData(width,height); bitmapData.draw(displayObject); var jPGEncoder:JPGEncoder = new JPGEncoder(quality); var byteArray:ByteArray = jPGEncoder.encode(bitmapData); var fileReference:FileReference = new FileReference(); fileReference.save(byteArray,"image.jpg"); } } 矩形選択ツール