forked from: Mediator パターンによるプログラム構築例(1)

by kinoppy forked from Mediator パターンによるプログラム構築例(1) (diff: 1)
Mediator パターンによるプログラム構築例(1)
@author Aquioux(Yoshida, Akio)
♥0 | Line 304 | Modified 2010-12-08 20:16:24 | MIT License
play

ActionScript3 source code

/**
 * Copyright kinoppy ( http://wonderfl.net/user/kinoppy )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xROv
 */

// forked from Aquioux's Mediator パターンによるプログラム構築例(1)
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;
        }
    }