/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/2Rqo
*/
package {
import flash.display.Sprite;
[SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#FFFFFF")]
/**
* Mediator パターンによるプログラム構築例(1)
* @author Aquioux(Yoshida, Akio)
*/
public class Main extends Sprite {
public function Main():void {
var mediator:Mediator = new Mediator();
mediator.setup(stage);
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Stage;
import flash.geom.Point;
/**
* Mediator
* @author YOSHIDA, Akio (Aquioux)
*/
class Mediator {
// ---------- パブリックプロパティ ----------
// 共用されるデータは Mediator が保持する
//
// BitmapData
public function get bitmapData():BitmapData { return _bitmapData; }
public function set bitmapData(value:BitmapData):void { _bitmapData = value; }
private var _bitmapData:BitmapData;
// スライダーの値
public function get value():Number { return _value; }
public function set value(value:Number):void { _value = value; }
private var _value:Number = 0;
// 処理状態
public function get state():String { return _state; }
public function set state(value:String):void { _state = value; }
private var _state:String;
// 処理状態の種類
public const LOAD:String = "load";
public const SAVE:String = "save";
// ---------- ローカルプロパティ ----------
//
// 各 Colleague
private var loadButton_:ExPushButton;
private var saveButton_:ExPushButton;
private var slider_:ExHSlider;
private var fileRefUnit_:FileRefUnit;
private var processer_:ImageProcesser;
private var viewer_:ExBitmap;
// ステージサイズ
private var sw_:uint;
private var sh_:uint;
// スライダーのパラメータ
private const MIN:Number = -1;
private const MAX:Number = 1;
private const DEF:Number = 0;
// 読み込んだ BitmapData の待避
private var saveBmd_:BitmapData;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
*/
public function Mediator() {
}
/**
* セットアップ
*/
public function setup(stage:Stage):void {
// 各 Colleague の生成
loadButton_ = new ExPushButton(LOAD.toUpperCase(), stage);
saveButton_ = new ExPushButton(SAVE.toUpperCase(), stage);
slider_ = new ExHSlider(stage);
fileRefUnit_ = new FileRefUnit();
processer_ = new ImageProcesser();
viewer_ = new ExBitmap();
// 各 Colleague に mediator をセット
loadButton_.mediator = this;
saveButton_.mediator = this;
slider_.mediator = this;
fileRefUnit_.mediator = this;
processer_.mediator = this;
viewer_.mediator = this;
// 個別 Colleague のセットアップ
// ボタン
saveButton_.width = loadButton_.width = 50;
saveButton_.x = loadButton_.width;
saveButton_.enabled = false;
// スライダー
slider_.width = stage.stageWidth;
slider_.y = stage.stageHeight - slider_.height;
slider_.enabled = false;
// ビューア
stage.addChild(viewer_);
// 処理状態更新
_state = LOAD;
// ステージサイズ
sw_ = stage.stageWidth;
sh_ = stage.stageHeight;
}
/**
* 各 Colleague から呼び出されるメソッド
*/
public function notify(colleague:IColleague):void {
// 呼び出し元が ExPushButton
if (colleague is ExPushButton) {
// FileRefUnit に通知
fileRefUnit_.update();
}
// 呼び出し元が FileRefUnit
if (colleague is FileRefUnit) {
if (_state == LOAD) {
// 読み込んだ BitmapData を待避
saveBmd_ = _bitmapData.clone();
// ImageProcesser に通知
processer_.update();
// 処理状態更新
_state = SAVE;
// ボタン更新
loadButton_.enabled = false;
saveButton_.enabled = true;
// スライダー更新
slider_.enabled = true;
slider_.setParams(MIN, MAX, DEF);
} else if (_state == SAVE) {
// 処理状態更新
_state = LOAD;
// ボタン更新
loadButton_.enabled = true;
saveButton_.enabled = false;
// スライダー更新
slider_.enabled = false;
}
}
// 呼び出し元が ImageProcesser
if (colleague is ImageProcesser) {
// ExBitmap 位置調節
viewer_.x = (sw_ - _bitmapData.width) / 2;
viewer_.y = (sh_ - _bitmapData.height) / 2;
// ExBitmap に通知
viewer_.update();
}
// 呼び出し元が ExHSlider
if (colleague is ExHSlider) {
// 待避していた BitmapData を読込
_bitmapData = saveBmd_.clone();
// ImageProcesser に通知
processer_.update();
}
}
}
/**
* Colleague の interface
* @author Aquioux
*/
interface IColleague {
// Mediator の参照
function set mediator(value:Mediator):void;
// Mediator が呼び出すこの Colleague のメソッド
function update():void;
}
import com.bit101.components.PushButton;
import flash.display.DisplayObjectContainer;
import flash.events.MouseEvent;
/**
* Button
* @author YOSHIDA, Akio (Aquioux)
*/
class ExPushButton extends PushButton implements IColleague {
// ---------- パブリックプロパティ ----------
//
// Mediator の参照
public function set mediator(value:Mediator):void { _mediator = value; }
private var _mediator:Mediator;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
*/
public function ExPushButton(label:String, container:DisplayObjectContainer) {
super(container, 0, 0, label, buttonHandler);
}
/**
* Mediator から呼び出される
*/
public function update():void {
}
// ---------- ローカルメソッド ----------
//
// ボタンクリックイベントのハンドラ
private function buttonHandler(e:MouseEvent):void {
_mediator.notify(this);
}
}
import com.bit101.components.HSlider;
import flash.display.DisplayObjectContainer;
import flash.events.Event;
/**
* Slider
* @author YOSHIDA, Akio (Aquioux)
*/
class ExHSlider extends HSlider implements IColleague {
// ---------- パブリックプロパティ ----------
//
// Mediator の参照
public function set mediator(value:Mediator):void { _mediator = value; }
private var _mediator:Mediator;
// ---------- ローカルプロパティ ----------
//
private const RENGE:uint = 10; // スライド値の小数点有効桁数
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
*/
public function ExHSlider(container:DisplayObjectContainer) {
super(container, 0, 0, sliderHandler);
}
/**
* パラメータのセット
*/
public function setParams(min:Number, max:Number, def:Number):void {
super.setSliderParams(min * RENGE, max * RENGE, def);
}
/**
* Mediator から呼び出される
*/
public function update():void {
}
// ---------- ローカルメソッド ----------
//
// ボタンクリックイベントのハンドラ
private function sliderHandler(e:Event):void {
_mediator.value = e.target.value / RENGE;
_mediator.notify(this);
}
}
import com.adobe.images.PNGEncoder;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.geom.Matrix;
import flash.net.FileReference;
import flash.utils.ByteArray;
/**
* FileRefUnit
* @author YOSHIDA, Akio (Aquioux)
*/
class FileRefUnit implements IColleague {
// ---------- パブリックプロパティ ----------
//
// Mediator の参照
public function set mediator(value:Mediator):void { _mediator = value; }
private var _mediator:Mediator;
// 表示する縦 or 横の長い方の最大値
static public const MAX_SIZE:uint = 300;
// ---------- ローカルプロパティ ----------
//
private var fileRef_:FileReference;
private var loader_:Loader;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
*/
public function FileRefUnit() {
fileRef_ = new FileReference();
loader_ = new Loader();
}
/**
* Mediator から呼び出される
*/
public function update():void {
if (_mediator.state == _mediator.LOAD) load1Handler();
if (_mediator.state == _mediator.SAVE) save1Handler();
}
// ---------- ローカルメソッド ----------
//
// 画像ロード step 1 ファイル選択
private function load1Handler():void {
fileRef_.addEventListener(Event.SELECT, load2Handler);
fileRef_.browse();
}
// 画像ロード step 2 ファイル読込
private function load2Handler(e:Event):void {
fileRef_.removeEventListener(Event.SELECT, arguments.callee);
fileRef_.addEventListener(Event.COMPLETE, load3Handler);
fileRef_.load();
}
// 画像ロード step 3 ファイル読込完了
private function load3Handler(e:Event):void {
fileRef_.removeEventListener(Event.COMPLETE, arguments.callee);
loader_.loadBytes(fileRef_.data);
loader_.contentLoaderInfo.addEventListener(Event.COMPLETE, load4Handler);
}
// 画像ロード step 4 ファイル読込後の処理
private function load4Handler(e:Event):void {
loader_.contentLoaderInfo.removeEventListener(Event.COMPLETE, arguments.callee);
getBitmapData(Bitmap(loader_.content).bitmapData);
}
// bitmapData の取得
private function getBitmapData(bmd1:BitmapData):void {
// 読み込んだ画像ファイルの BitmapData の処理
var w:uint = bmd1.width;
var h:uint = bmd1.height;
var scale:Number = Math.min(MAX_SIZE / w, MAX_SIZE / h);
if (scale > 1) scale = 1;
var bmd2:BitmapData = new BitmapData(w * scale, h * scale);
bmd2.draw(bmd1, new Matrix(scale, 0, 0, scale));
_mediator.bitmapData = bmd2.clone();
_mediator.notify(this);
bmd1.dispose();
bmd2.dispose();
}
// 画像セーブ step 1 ファイル選択
private function save1Handler():void {
var png:ByteArray = PNGEncoder.encode(_mediator.bitmapData);
fileRef_.addEventListener(Event.SELECT, save2Handler);
fileRef_.save(png, "save.png");
}
// 画像セーブ step 2
private function save2Handler(event:Event):void {
fileRef_.removeEventListener(Event.SELECT, arguments.callee);
_mediator.notify(this);
}
}
import flash.display.BitmapData;
/**
* ImageProcesser
* @author YOSHIDA, Akio (Aquioux)
*/
class ImageProcesser implements IColleague {
// ---------- パブリックプロパティ ----------
//
// Mediator の参照
public function set mediator(value:Mediator):void { _mediator = value; }
private var _mediator:Mediator;
// ---------- ローカルプロパティ ----------
//
private var contrast_:Contrast;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
*/
public function ImageProcesser() {
contrast_ = new Contrast();
}
/**
* Mediator から呼び出される
*/
public function update():void {
var bmd:BitmapData = _mediator.bitmapData;
contrast_.strength = _mediator.value;
contrast_.applyEffect(bmd);
_mediator.bitmapData = bmd;
_mediator.notify(this);
}
}
import flash.display.Bitmap;
/**
* ExBitmap
* @author YOSHIDA, Akio (Aquioux)
*/
class ExBitmap extends Bitmap implements IColleague {
// ---------- パブリックプロパティ ----------
//
// Mediator の参照
public function set mediator(value:Mediator):void { _mediator = value; }
private var _mediator:Mediator;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
*/
public function ExBitmap() {
}
/**
* Mediator から呼び出される
*/
public function update():void {
bitmapData = _mediator.bitmapData;
}
}
import flash.geom.Point;
/**
* bitmapDataEffector パッケージ内のクラスで共通に使う定数など
* @author YOSHIDA, Akio (Aquioux)
*/
class EffectorUtils {
// ---------- パブリックプロパティ ----------
//
// BitmapData が備える各種メソッドの destPoint 用
static public const ZERO_POINT:Point = new Point(0, 0);
// グレイスケール用の各チャンネルの重みづけ
static public const LUM_R:Number = 0.298912;
static public const LUM_G:Number = 0.586611;
static public const LUM_B:Number = 0.114478;
// ---------- パブリックメソッド ----------
//
// 一つのチャンネルにおける濃度の平均値を求める(引数のヒストグラムで調整する)
static public function getAverageOfBrightness1(hist:Vector.<Number>):uint {
var sum:uint = 0;
var numOfPixel:uint = 0;
for (var i:int = 0; i < 256; i++) {
sum += i * hist[i];
numOfPixel += hist[i];
}
return sum / numOfPixel >> 0;
}
// RGB チャンネルにおける濃度の各平均値を求める
static public function getAverageOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
var rSum:uint = 0;
var gSum:uint = 0;
var bSum:uint = 0;
var numOfPixel:uint = 0;
for (var i:int = 0; i < 256; i++) {
rSum += i * hist[0][i];
gSum += i * hist[1][i];
bSum += i * hist[2][i];
numOfPixel += hist[0];
}
return Vector.<uint>([rSum / numOfPixel >> 0, gSum / numOfPixel >> 0, bSum / numOfPixel >> 0]);
}
// 一つのチャンネルにおける濃度の平均値を求める(引数のヒストグラムで調整する)
static public function getSumOfBrightness1(hist:Vector.<Number>):uint {
var sum:uint = 0;
for (var i:int = 0; i < 256; i++) {
sum += i * hist[i];
}
return sum;
}
// RGB チャンネルにおける濃度の各平均値を求める
static public function getSumOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
var rSum:uint = 0;
var gSum:uint = 0;
var bSum:uint = 0;
for (var i:int = 0; i < 256; i++) {
rSum += i * hist[0][i];
gSum += i * hist[1][i];
bSum += i * hist[2][i];
}
return Vector.<uint>([rSum, gSum, bSum]);
}
}
import flash.display.BitmapData;
/**
* BitmapDataEffector 用 interface
* @author YOSHIDA, Akio (Aquioux)
*/
interface IEffector {
function applyEffect(value:BitmapData):BitmapData;
}
import flash.display.BitmapData;
import flash.filters.ColorMatrixFilter;
import flash.geom.Point;
/**
* コントラスト
* @author YOSHIDA, Akio (Aquioux)
*/
class Contrast implements IEffector {
// ---------- パブリックプロパティ ----------
//
/*
* コントラストの強さ
* @param value 強さ
*/
public function set strength(value:Number):void {
// value の有効範囲は -1 ~ 1
if (value < -1) value = -1;
if (value > 1) value = 1;
value += 1;
matrix_ = [
value, 0, 0, 0, 128 * (1 - value),
0, value, 0, 0, 128 * (1 - value),
0, 0, value, 0, 128 * (1 - value),
0, 0, 0, 1, 0
];
filter_.matrix = matrix_;
}
// ---------- ローカルプロパティ ----------
//
private var matrix_:Array = [
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0
];
private var filter_:ColorMatrixFilter = new ColorMatrixFilter(matrix_);
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
// ---------- パブリックメソッド ----------
//
/*
* コンストラクタ
*/
public function Contrast() {
}
/*
* 効果適用
* @param value 効果対象 BitmapData
*/
public function applyEffect(value:BitmapData):BitmapData {
value.applyFilter(value, value.rect, ZERO_POINT, filter_);
return value;
}
}