In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Dither

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

package {
    import flash.geom.Matrix;
    //import aquioux.display.bitmapDataEffector.GrayScale;
    //import aquioux.utils.ButtonMediator;
    import com.bit101.components.PushButton;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    /**
     * ハーフトーニング(ランダムディザと組織的ディザ)
     * @see    http://aquioux.net/blog/?p=2688
     * @author YOSHIDA, Akio (Aquioux)
     */
    [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#FFFFFF")]
 

    public class Main extends Sprite {
        // ビューア BitmapData
        private var viewBmd_:BitmapData;

        // BitmapData#getVector で得られる値
        private var sourcePixelList_:Vector.<uint>;    // ソース画像
        private var grayPixelList_:Vector.<uint>;    // グレイスケール画像

        // BitmapData#setVector 用
        private var rect_:Rectangle;

        // ディザクラス
        private var randomDither_:RandomDither;        // ランダムディザ法
        private var orderedDither_:OrderedDither;    // 組織的ディザ法

        // ボタン管理
        private var buttonMediator_:ButtonMediator;


        // コンストラクタ
        public function Main() {
            var url:String = "http://assets.wonderfl.net/images/related_images/3/39/39f6/39f64cad1c50914c2c459386feeddf6d915cea06m";
            var loader:Loader = new Loader();
            loader.load(new URLRequest(url), new LoaderContext(true));
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
        }

        private function completeHandler(event:Event):void {
            // ソースイメージ
            var loadedBmd:BitmapData = event.target.loader.content.bitmapData;
            var sourceBmd:BitmapData = new BitmapData(180, 215);
            sourceBmd.draw(loadedBmd, new Matrix(180/200, 0, 0, 215/200));
            rect_ = sourceBmd.rect;
            sourcePixelList_ = sourceBmd.getVector(rect_);
            
            // グレイスケール BitmapData
            var grayBmd:BitmapData = sourceBmd.clone();
            new GrayScale().applyEffect(grayBmd);
            grayPixelList_ = grayBmd.getVector(rect_);
            grayBmd.dispose();

            // ビューア
            viewBmd_ = sourceBmd;
            var viewBm:Bitmap = new Bitmap(viewBmd_);
            viewBm.x = (stage.stageWidth  - viewBm.width )  / 2 >> 0;
            viewBm.y = (stage.stageHeight - viewBm.height ) / 2 >> 0;
            addChild(viewBm);

            // ディザクラス
            randomDither_  = new RandomDither();
            orderedDither_ = new OrderedDither();

            // ボタン
            var buttonWidth:int  = 50;
            var buttonHeight:int = 20;
            var button0:PushButton = new PushButton(this, 0, buttonHeight * 0, "Random", random);
            var button1:PushButton = new PushButton(this, 0, buttonHeight * 1, "Bayer", bayer);
            var button2:PushButton = new PushButton(this, 0, buttonHeight * 2, "Halftone", halftone);
            var button3:PushButton = new PushButton(this, 0, buttonHeight * 3, "Screw", screw);
            var button4:PushButton = new PushButton(this, 0, buttonHeight * 4, "Screw2", screw2);
            var button5:PushButton = new PushButton(this, 0, buttonHeight * 5, "Center", center);
            var button6:PushButton = new PushButton(this, 0, buttonHeight * 6, "Dot", dot);
            var button7:PushButton = new PushButton(this, 0, buttonHeight * 7, "Original", originalHander);
            button0.width  = buttonWidth;
            button1.width  = buttonWidth;
            button2.width  = buttonWidth;
            button3.width  = buttonWidth;
            button4.width  = buttonWidth;
            button5.width  = buttonWidth;
            button6.width  = buttonWidth;
            button7.width  = buttonWidth;
            button0.height = buttonHeight;
            button1.height = buttonHeight;
            button2.height = buttonHeight;
            button3.height = buttonHeight;
            button4.height = buttonHeight;
            button5.height = buttonHeight;
            button6.height = buttonHeight;
            button7.height = buttonHeight;

            // ボタン管理
            buttonMediator_ = new ButtonMediator();
            buttonMediator_.prevButton = button7;
        }
        
        // オリジナル画像
        private function originalHander(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            viewBmd_.setVector(rect_, sourcePixelList_);
        }

        // ランダムディザ
        private function random(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            // ディザ実行
            viewBmd_.setVector(rect_, grayPixelList_);
            randomDither_.execute(viewBmd_);
        }

        // 組織的ディザ(Bayer 型)
        private function bayer(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            // ディザ実行
            viewBmd_.setVector(rect_, grayPixelList_);
            orderedDither_.matrix = Vector.<uint>([
                 0,  8,  2, 10,
                12,  4, 14,  6,
                 3, 11,  1,  9,
                15,  7, 13,  5
            ]);
            orderedDither_.execute(viewBmd_);
        }
        // 組織的ディザ(ハーフトーン型)
        private function halftone(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            // ディザ実行
            viewBmd_.setVector(rect_, grayPixelList_);
            orderedDither_.matrix = Vector.<uint>([
                10,  4,  6,  8,
                12,  0,  2, 14,
                 7,  9, 11,  5,
                 3, 15, 13,  1
            ]);
            orderedDither_.execute(viewBmd_);
        }
        // 組織的ディザ(screw 型)
        private function screw(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            // ディザ実行
            viewBmd_.setVector(rect_, grayPixelList_);
            orderedDither_.matrix = Vector.<uint>([
                13,  7,  6, 12,
                 8,  1,  0,  5,
                 9,  2,  3,  4,
                14, 10, 11, 15
            ]);
            orderedDither_.execute(viewBmd_);
        }
        // 組織的ディザ(screw 変形型)
        private function screw2(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            // ディザ実行
            viewBmd_.setVector(rect_, grayPixelList_);
            orderedDither_.matrix = Vector.<uint>([
                15,  4,  8, 12,
                11,  0,  1,  5,
                 7,  3,  2,  9,
                14, 10,  6, 13
            ]);
            orderedDither_.execute(viewBmd_);
        }
        // 組織的ディザ(中間調強調型)
        private function center(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            // ディザ実行
            viewBmd_.setVector(rect_, grayPixelList_);
            orderedDither_.matrix = Vector.<uint>([
                12,  4,  8, 14,
                11,  0,  2,  6,
                 7,  3,  1, 10,
                15,  9,  5, 13
            ]);
            orderedDither_.execute(viewBmd_);
        }
        // 組織的ディザ(Dot Concentrate 型)
        private function dot(event:Event):void {
            // ボタンの処理
            buttonMediator_.buttonChange(PushButton(event.target));
            // ディザ実行
            viewBmd_.setVector(rect_, grayPixelList_);
            orderedDither_.matrix = Vector.<uint>([
                12,  4,  8, 14,
                10,  0,  1,  7,
                 6,  3,  2, 11,
                15,  9,  5, 13
            ]);
            orderedDither_.execute(viewBmd_);
        }
    }
}


//package {
    import flash.display.BitmapData;
    import flash.geom.Rectangle;
    /**
     * ランダムディザ
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class RandomDither {
        /**
         * コンストラクタ
         */
        public function RandomDither() {
        }
        
        /**
         * ディザ実行
         */
        public function execute(bmd:BitmapData):void {
            var rect:Rectangle = bmd.rect;

            var pixelList:Vector.<uint> = bmd.getVector(rect);
            // 走査
            var len:uint = pixelList.length;
            for (var i:int = 0; i < len; i++) {
                var threshold:int = Math.random() * 0xFF >> 0;
                var gray:uint     = pixelList[i] & 0xFF;
                pixelList[i]      = gray > threshold ? 0xFFFFFFFF : 0xFF000000;
            }
            bmd.setVector(rect, pixelList);
        }
    }
//}


//package {
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.geom.Rectangle;
    /**
     * 組織的ディザ
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class OrderedDither extends EventDispatcher {
        /**
         * ディザ・マトリクス
         */
        public function set matrix(value:Vector.<uint>):void {
            _matrix = value;
            var len:int = _matrix.length;
            for (var i:int = 0; i < len; i++) _matrix[i] = _matrix[i] * 16 + 8;
        }
        private var _matrix:Vector.<uint> = Vector.<uint>([
             0,  8,  2, 10,
            12,  4, 14,  6,
             3, 11,  1,  9,
            15,  7, 13,  5
        ]);    // Bayer 型
        

        /**
         * コンストラクタ
         */
        public function OrderedDither() {
            matrix = _matrix;
        }

        /**
         * ディザ実行
         */
        public function execute(bmd:BitmapData):void {
            var imageWidth:int = bmd.width;
            var rect:Rectangle = bmd.rect;

            var pixelList:Vector.<uint> = bmd.getVector(rect);
            // 走査
            var len:uint = pixelList.length;
            for (var i:int = 0; i < len; i++) {
                var idxX:int = (i % imageWidth)      % 4;
                var idxY:int = (i / imageWidth >> 0) % 4;
                var threshold:int = _matrix[idxY * 4 + idxX];
                var gray:uint     = pixelList[i] & 0xFF;
                pixelList[i]      = gray >= threshold ? 0xFFFFFFFF : 0xFF000000;
            }
            bmd.setVector(rect, pixelList);
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
//}


//package aquioux.display.bitmapDataEffector {
    import flash.display.BitmapData;
    import flash.filters.ColorMatrixFilter;
    import flash.geom.Point;
    /**
     * ColorMatrixFilter による BitmapData のグレイスケール化(NTSC 系加重平均による)
     * 参考:Foundation ActionScript 3.0 Image Effects(P106)
     *         http://www.amazon.co.jp/gp/product/1430218711?ie=UTF8&tag=laxcomplex-22
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class GrayScale implements IEffector {
        private const R:Number = EffectorUtils.LUM_R;
        private const G:Number = EffectorUtils.LUM_G;
        private const B:Number = EffectorUtils.LUM_B;

        private const MATRIX:Array = [
            R, G, B, 0, 0,
            R, G, B, 0, 0,
            R, G, B, 0, 0,
            0, 0, 0, 1, 0
        ];
        private const FILTER:ColorMatrixFilter = new ColorMatrixFilter(MATRIX);

        private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
        

        /*
         * 効果適用
         * @param    value    効果対象 BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            value.applyFilter(value, value.rect, ZERO_POINT, FILTER);
            return value;
        }
    }
//}


//package aquioux.display.bitmapDataEffector {
    import flash.display.BitmapData;
    /**
     * BitmapDataEffector 用 interface
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ interface IEffector {
        function applyEffect(value:BitmapData):BitmapData;
    }
//}


//package aquioux.display.bitmapDataEffector {
    import flash.geom.Point;
    /**
     * bitmapDataEffector パッケージ内のクラスで共通に使う定数など
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class EffectorUtils {
        // BitmapData が備える各種メソッドの destPoint 用
        static public const ZERO_POINT:Point = new Point(0, 0);

        // グレイスケール用の各チャンネルの重みづけ
        // NTSC系加重平均法(YIQ,YCbCr も同じ)
        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 const LUM_R:Number = 1/3;
        //static public const LUM_G:Number = 1/3;
        //static public const LUM_B:Number = 1/3;

        // HDTV
        //static public const LUM_R:Number = 0.2126;
        //static public const LUM_G:Number = 0.7152;
        //static public const LUM_B:Number = 0.0722;
    }
//}


//package aquioux.utils {
    /**
     * 複数あるボタンの調停
     * 一度押したボタンは、別のボタンが押されるまで無効になる
     * @author Aquioux(Yoshida, Akio)
     */
    import com.bit101.components.PushButton;

    /*public*/ class ButtonMediator {
        // 前回押したボタン
        public function set prevButton(value:PushButton):void {
            _prevButton = value;
            _prevButton.enabled = false;    // 無効にする
        }
        private var _prevButton:PushButton;


        /**
         * コンストラクタ
         */
        public function ButtonMediator() {
        }


        /**
         * ボタン切り替え
         * @param    button    今回押したボタン
         */
        public function buttonChange(button:PushButton):void {
            // 前回押したボタンを有効に戻す
            if (_prevButton != null) _prevButton.enabled = true;
            // 今回押したボタンを前回押したボタンにして、無効にする
            prevButton = button;
        }
    }
//}