PixelClip


「Load IMG」ボタンで画像をステージに読み込んで、マウスで矩形を作って、jpg/pngで書き出すことができる。

重いPhotoShop(FireWorks)を起動しても
やりたいことは

・画像の座標を知りたい。
・色番号を知りたい。
・矩形の幅を知りたい。
・切り抜いて書き出し(透明の1pxの枠つけたり)。

だけだったりすることがある。
これくらいなら、ASでつくれるかも??

まずは頭の整理のために基礎部分を作ってみた。

[今後の参考]GIMP矩形ツール
http://iccii.seesaa.net/article/28058268.html

▼Wonderfl
http://wonderfl.net/code/73a97c1fb612becdd69aa2643976ce30497365ee

▼ActionScript AS3(FP10)
[sourcecode language="as3"]
/*
PixelClip

「Load IMG」ボタンで画像をステージに読み込んで、
マウスで矩形を作って、jpg/pngで書き出すことができる。
===========================================
重いPhotoShop(FireWorks)を起動しても
やりたいことは

・画像の座標を知りたい。
・色番号を知りたい。
・矩形の幅を知りたい。
・切り抜いて書き出し(透明の1pxの枠つけたり)。

だけだったりすることがある。
これくらいなら、ASでつくれるかも??

まずは頭の整理のために基礎部分を作ってみた。

[今後の参考]GIMP矩形ツール
http://iccii.seesaa.net/article/28058268.html
*/

package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;

[SWF(backgroundColor="0x777777")]
public class Main extends Sprite
{
private var _highlite:Highlite;
private var _imageCanvas:Sprite;
private var _toolsBar:ToolsBar;
private var _targetBitmap:Bitmap;
public function Main()
{
stage.scaleMode = "noScale";
stage.align = "TL";
stage.addEventListener(Event.RESIZE,onResize);

_imageCanvas = new Sprite();
this.addChild(_imageCanvas);

_highlite = new Highlite();
this.addChild(_highlite);

_toolsBar = new ToolsBar();
_toolsBar.x = Math.floor((stage.stageWidth-_toolsBar.width)/2);
_toolsBar.y = stage.stageHeight-82;
_toolsBar.atLoadComp = atLoadComp;
_toolsBar.atTextChange = atTextChange;
this.addChild(_toolsBar);

stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown);
stage.addEventListener(MouseEvent.MOUSE_MOVE,onMove);
}
private function atTextChange(a:Point,b:Point):void{
_highlite.atTextChange(a,b);
atSelect();
}
private function onResize(event:Event):void{
_toolsBar.x = Math.floor((stage.stageWidth-_toolsBar.width)/2);
_toolsBar.y = stage.stageHeight-82;
_imageCanvas.x = Math.floor((stage.stageWidth-_targetBitmap.width)/2);
_imageCanvas.y = Math.floor((stage.stageHeight-_targetBitmap.height-_toolsBar.height)/2);
_highlite.rectangle.x = _highlite.x = _imageCanvas.x;
_highlite.rectangle.y = _highlite.y = _imageCanvas.y;
}
private function atSelect():void{
if(_highlite.selectedRectangle == null){return};
if(_highlite.selectedRectangle.width*_highlite.selectedRectangle.height<=0){return};
var bitmapData:BitmapData = new BitmapData(_highlite.selectedRectangle.width,_highlite.selectedRectangle.height);
bitmapData.draw(_targetBitmap,new Matrix(1,0,0,1,-_highlite.selectedRectangle.x,-_highlite.selectedRectangle.y));
var bitmap:Bitmap = new Bitmap(bitmapData);
_toolsBar.atSelect(_highlite.selectedRectangle,bitmap);
}
private function atLoadComp(bitmap:Bitmap):void{
while (_imageCanvas.numChildren > 0) {
_imageCanvas.removeChildAt(0);
}
_imageCanvas.addChild(bitmap);
_imageCanvas.x = Math.floor((stage.stageWidth-bitmap.width)/2);
_imageCanvas.y = Math.floor((stage.stageHeight-bitmap.height-_toolsBar.height)/2);
var monoglam:Shape = getBGMonoglam(bitmap.width,bitmap.height);
_imageCanvas.addChildAt(monoglam,0);

_highlite.rectangle = new Rectangle(_imageCanvas.x,_imageCanvas.y,bitmap.width,bitmap.height);
_highlite.clear();
_targetBitmap = bitmap;
}

private function onDown(event:MouseEvent):void{
_highlite.onDown();
}
private function onMove(event:MouseEvent):void{
if(!event.buttonDown){return};
_highlite.onMove();
atSelect();
}
private function getBGMonoglam(width:int, height:int):Shape {
var patern:BitmapData = new BitmapData(2, 2, false,0xFFFFFF);
patern.setPixel(0, 1, 0xCCCCCC);
patern.setPixel(1, 0, 0xCCCCCC);
var shape:Shape = new Shape();
shape.graphics.beginBitmapFill(patern, new Matrix(8, 0, 0, 8));
shape.graphics.drawRect(0, 0, width, height);
shape.graphics.endFill();
return shape;
}
}
}

import com.bit101.components.CheckBox;
import com.bit101.components.HSlider;
import com.bit101.components.Label;
import com.bit101.components.Panel;
import com.bit101.components.PushButton;

import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;

class ToolsBar extends Sprite{
private var _hSlider:HSlider;
private var _is32BitColor:CheckBox;
private var _isClearEdge:CheckBox;
private var _isEven:CheckBox;
private var _jpgLavel:Label;
private var _loadImgTF:TextField;
private var _selectedTF:TextField;
private var _selectedTFx:NumericTextField;
private var _selectedTFy:NumericTextField;
private var _selectedTFwidth:NumericTextField;
private var _selectedTFheight:NumericTextField;
private var _selectedTFarray:Array;
private var _loadImgColorChip:Shape;
private var _selectedColorChip:Shape;
private var _selectedBitmap:Bitmap;
public var atTextChange:Function = function(a:Point,b:Point):void{};
public var atLoadComp:Function = function(bitmap:Bitmap):void{};
public function ToolsBar(){

var panelLoad:Panel = new Panel(this,0,0);
panelLoad.width = 116;
panelLoad.height = 82;
new PushButton(panelLoad,8,8,"Load IMG",atLoadClick);

var panelJPG:Panel = new Panel(this,116*2,0);
panelJPG.width = 116;
panelJPG.height = 82;
_jpgLavel = new Label(panelJPG,8,4,"Quality:90");
_hSlider = new HSlider(panelJPG,8,8+16,atJPGSlider);
_hSlider.value = 90;
new PushButton(panelJPG,8,8+16*3,"SAVE JPG",atJPGClick);

var panelPNG:Panel = new Panel(this,116*3,0);
panelPNG.width = 116;
panelPNG.height = 82;
_is32BitColor = new CheckBox(panelPNG,8,8,"32 Bit Color");
_is32BitColor.selected = true;
_isClearEdge = new CheckBox(panelPNG,8,8+16,"Clear Edge");
_isEven = new CheckBox(panelPNG,8,8+16*2,"Even");
new PushButton(panelPNG,8,8+16*3,"SAVE PNG",atPNGClick);

_loadImgTF = new TextField();
_loadImgTF.defaultTextFormat = new TextFormat("_sans", 9, "0x555555",null,null,null,null,null,null,null,null,null,2);
_loadImgTF.text = "width:0\nheight:0\ncolor average";
_loadImgTF.x = 8;
_loadImgTF.y = 28;
_loadImgTF.width = 100;
_loadImgTF.height = 50;
panelLoad.addChild(_loadImgTF);
_loadImgColorChip = new Shape();
_loadImgColorChip.x = 90;
_loadImgColorChip.y = 55;
panelLoad.addChild(_loadImgColorChip);

var panelData:Panel = new Panel(this,116,0);
panelData.width = 116;
panelData.height = 82;

_selectedTF = new TextField();
_selectedTF.defaultTextFormat = new TextFormat("_sans", 9, "0x555555");
_selectedTF.text = "color average";
_selectedTF.x = 8;
_selectedTF.y = 5+12*4;
_selectedTF.width = 100;
_selectedTF.height = 82-8;
panelData.addChild(_selectedTF);
_selectedColorChip = new Shape();
_selectedColorChip.x = 90;
_selectedColorChip.y = 55;
panelData.addChild(_selectedColorChip);

var templeteNTF:Object = {step:1,isKeyboardControl:true,minimum:0,maximum:4080,numeric:0,onChange:onTextChange};
var templeteTF:Object = {autoSize:"left",type:"input"};
var tx:Array = ["x:","y:","width:","height:"];
_selectedTFarray = [];
var n:int = tx.length;
for (var i:int = 0; i < n; i++) {
var tf:TextField = new TextField();
tf.defaultTextFormat = new TextFormat("_sans", 9, "0x555555");
tf.text = tx[i];
tf.x = 8;
tf.y = 5+12*i;
tf.autoSize = "left";
tf.selectable = false;
panelData.addChild(tf);
_selectedTFarray[i] = new NumericTextField({defaultTextFormat:new TextFormat("_sans", 9, "0x555555")},templeteNTF,templeteTF);
_selectedTFarray[i].x = int(tf.x+tf.width);
_selectedTFarray[i].y = 5+12*i;
_selectedTFarray[i].addEventListener(Event.CHANGE,onTextChange);
panelData.addChild(_selectedTFarray[i]);
}

}
private function onTextChange(event:Event = null):void{
var a:Point = new Point(_selectedTFarray[0].numeric,_selectedTFarray[1].numeric);
var b:Point = new Point(_selectedTFarray[2].numeric+_selectedTFarray[0].numeric,_selectedTFarray[3].numeric+_selectedTFarray[1].numeric);
atTextChange(a,b);
}
private function atLoadClick(event:MouseEvent):void{
var loadFile:LoadFile = new LoadFile();
loadFile.atComplete = atLoadComplete;
loadFile.start();
}
private function atLoadComplete(event:Event):void{
atLoadComp(event.target.content);
var bitmapData:BitmapData = new BitmapData(event.target.content.width,event.target.content.height);
bitmapData.draw(event.target.content);
var rgb:uint = getColorAverage(bitmapData);
_loadImgTF.text = "width:"+event.target.content.width+"\nheight:"+event.target.content.height+"\nave."+"0x"+rgb.toString(16).toUpperCase();
_loadImgColorChip.graphics.clear();
_loadImgColorChip.graphics.beginFill(rgb%0x1000000,(rgb >> 24 & 0xFF)/0xFF);
_loadImgColorChip.graphics.drawRect(0,0,9,9);
_loadImgColorChip.graphics.endFill();

}
public function atSelect(selectedRectangle:Rectangle,bitmap:Bitmap):void{
var bitmapData:BitmapData = new BitmapData(selectedRectangle.width,selectedRectangle.height);
bitmapData.draw(bitmap);
var rgb:uint = getColorAverage(bitmapData);
_selectedTF.text = "ave."+"0x"+rgb.toString(16).toUpperCase();
_selectedTFarray[0].numeric = selectedRectangle.x;
_selectedTFarray[1].numeric = selectedRectangle.y;
_selectedTFarray[2].numeric = selectedRectangle.width;
_selectedTFarray[3].numeric = selectedRectangle.height;

_selectedColorChip.graphics.clear();
_selectedColorChip.graphics.beginFill(rgb%0x1000000,(rgb >> 24 & 0xFF)/0xFF);
_selectedColorChip.graphics.drawRect(0,0,9,9);
_selectedColorChip.graphics.endFill();
_selectedBitmap = bitmap;
}
private function getColorAverage(bitmapData:BitmapData):uint{
var w:int = bitmapData.width;
var h:int = bitmapData.height;
var n:int = w*h;
var a:uint;
var r:uint;
var g:uint;
var b:uint;
for (var i:int = 0; i < n; i++) {
var argb:uint = bitmapData.getPixel32(i%w,Math.floor(i/w));
a += argb >> 24 & 0xFF;
r += argb >> 16 & 0xFF;
g += argb >> 8 & 0xFF;
b += argb & 0xFF;
}
a = Math.floor(a/n);
r = Math.floor(r/n);
g = Math.floor(g/n);
b = Math.floor(b/n);
return ((a*0x1000000+r*0x10000+g*0x100+b));
}
private function atPNGClick(event:MouseEvent):void{
if(_selectedBitmap.width*_selectedBitmap.height){
SaveImage.PNGfromDisplayObject(_selectedBitmap,_is32BitColor.selected,_isClearEdge.selected,_isEven.selected);
}
}
private function atJPGClick(event:MouseEvent):void{
if(_selectedBitmap.width*_selectedBitmap.height){
SaveImage.JPGfromDisplayObject(_selectedBitmap,Number(_jpgLavel.text.substr(8)));
}
}
private function atJPGSlider(event:Event):void{
_jpgLavel.text = String("Quality:"+Math.round(event.target.value));
}

}

import flash.display.Shape;
import flash.geom.Point;
import flash.geom.Rectangle;
class Highlite extends Shape{
private var _down:Point;
public var selectedRectangle:Rectangle;
private var _rectangle:Rectangle;
public function Highlite(x:Number=0,y:Number=0,width:Number=0,height:Number=0){
rectangle = new Rectangle(x,y,width,height);
_down = new Point();
};
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);
this.graphics.endFill();
selectedRectangle = new Rectangle(x,y,w,h);
}
public function atTextChange(a:Point,b:Point):void{
target(a,b);
}
public function set rectangle(rect:Rectangle):void{
this.x = rect.x;
this.y = rect.y;
_rectangle = rect;
}
public function get rectangle():Rectangle{
return _rectangle;
}
public function clear():void{
this.graphics.clear();
}
public function onDown():void{
_down = new Point(this.mouseX,this.mouseY);
}
public function onMove():void{
var up:Point = new Point(this.mouseX,this.mouseY);
target(_down,up);
}
}

import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.text.TextField;

class NumericTextField extends TextField{
private var _base:int = 10;
private var _isDecimalPoint:Boolean = true;
private var _isKeyboardControl:Boolean;
private var _isUpperCase:Boolean = true;
private var _length:int = -1;
private var _maximum:Number = Infinity;
private var _minimum:Number = -Infinity;
private var _numeric:Number;
private var _isPrefix:Boolean;
private var _step:Number =1;
public function NumericTextField(... args){
for (var i:int = 0; i < args.length; i++) {
var params:Object = args[i];
for (var str:String in params) {
this[str] = params[str];
}
}
this.addEventListener(Event.ADDED_TO_STAGE,atAddedToStage);
}
private function atAddedToStage(event:Event):void{
this.removeEventListener(Event.ADDED_TO_STAGE,atAddedToStage);
this.addEventListener(Event.REMOVED_FROM_STAGE,atRemoverFromStage);
//isKeyboardControl = _isKeyboardControl;
}
private function atRemoverFromStage(event:Event):void{
this.removeEventListener(Event.REMOVED_FROM_STAGE,atRemoverFromStage);
this.removeEventListener(KeyboardEvent.KEY_DOWN,atKeyboardEvent);
}
private function atKeyboardEvent(event:KeyboardEvent):void{
if(event.keyCode == 38){
numeric += _step;
}else if(event.keyCode == 40){
numeric -= _step;
}
}
public var onChange:Function = function():void{};
/**
* 基数(value進数)の設定。デフォルトは10進数。10/16/2の設定ができる。
*/
public function get base():int{return _base;};
public function set base(value:int):void{
if(value != 16 && value != 10 && value != 2){return};
_base = value;
if(value == 16){
if(_isPrefix){
this.restrict = "A-F a-f 0-9 x";
}else{
this.restrict = "A-F a-f 0-9";
}
}else if(value == 10){
if(_isDecimalPoint){
this.restrict = "0-9 \.";
}else{
this.restrict = "0-9";
}
}else if(value == 2){
this.restrict = "0-1";
}
setText();
}
/**
* 小数点入力の可否。デフォルトは可
*/
public function get isDecimalPoint():Boolean{return _isDecimalPoint;};
public function set isDecimalPoint(value:Boolean):void{
if(_isDecimalPoint == value){return};
_isDecimalPoint = value;
if(_base == 10){
if(value){
this.restrict = "0-9 \.";
}else{
this.restrict = "0-9";
}
}
}
/**
* キーボードでのコントロールをするか否か。デフォルトは否
*/
public function get isKeyboardControl():Boolean{return _isKeyboardControl;};
public function set isKeyboardControl(value:Boolean):void{
if(_isKeyboardControl == value){return};
_isKeyboardControl = value;
if(value){
this.removeEventListener(KeyboardEvent.KEY_DOWN,atKeyboardEvent);
this.addEventListener(KeyboardEvent.KEY_DOWN,atKeyboardEvent);
}else{
this.removeEventListener(KeyboardEvent.KEY_DOWN,atKeyboardEvent);
}
}
/**
* プレフィックス(0x)を付けるか否か。デフォルトはつけない
*/
public function get isPrefix():Boolean{return _isPrefix;};
public function set isPrefix(value:Boolean):void{
if(_isPrefix == value){return};
_isPrefix = value;
if(_base == 16){
if(value){
this.restrict = "A-F a-f 0-9 x";
}else{
this.restrict = "A-F a-f 0-9";
}
}
setText();
}
/**
* 大文字か小文字か。デフォルトは大文字
*/
public function get isUpperCase():Boolean{return _isUpperCase;};
public function set isUpperCase(value:Boolean):void{
if(_isUpperCase == value){return};
_isUpperCase = value;
setText();
}
/**
* int型でテキストの桁数指定。-1でなりゆき。デフォルトは-1;
*/
public function set length(value:int):void{
if(_length == value){return};
_length = value;
setText();
}
/**
* Number型でテキストを設定。デフォルトは0
*/
public function get numeric():Number{
var string:String = super.text;
if(string.substr(0,2) != "0x" && base == 16){
return Number("0x"+super.text);
}else{
return Number(super.text);
}
};
public function set numeric(value:Number):void{
if(_numeric == value){return};
if(!isNaN(value)){
_numeric = Math.max(Math.min(value,_maximum),_minimum);
}else{
//_numeric = minimum;
};
setText();
}
/**
* 一回のキー押し下げでどれくらい値が変わるか。デフォルトは1
*/
public function get step():Number{return _step;};
public function set step(value:Number):void{
if(_step == value){return};
_step = value;
}
/**
* 最大値。デフォルトはInfinity
*/
public function get maximum():Number{return _maximum;};
public function set maximum(value:Number):void{
if(_maximum == value){return};
_maximum = value;
numeric = Math.min(value,_numeric);
}
/**
* 最小値。デフォルトは-Infinity
*/
public function get minimum():Number{return _minimum;};
public function set minimum(value:Number):void{
if(_minimum == value){return};
_minimum = value;
numeric = Math.max(value,_numeric);
}
override public function set text(value:String):void{
if(super.text == value){return};
if(base == 16){
if(_isPrefix){
numeric = Number(value);
}else{
numeric = Number("0x"+value);
}
}else if(base == 10){
numeric = Number(value);
}else if(base == 2){
numeric = Number(value);
}
}
private function setText():void{
var string:String = _numeric.toString(_base);
if(string == "NaN"){
string = "";
}
if(_isUpperCase){
string = string.toUpperCase();
}
if(_length > 0){
string = ("0000000000000000000000000000000000000000000000000000000000000000"+string).substr(-_length);
}
if(_isPrefix && _base == 16 && _length > 0){
string = "0x"+string;
}
super.text = string;

if(this.stage && this.root.stage.focus == this){
onChange();
}
}
}

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");
}
}
[/sourcecode]