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

forked from: forked from: [WebCam] 誰でもスーラ -Anyone Seurat-

誰でもスーラ -Anyone Seurat-
点描派風ピクセレート・ウェブカム版
ネタ元:Beyond Interaction -メディアアートのための openFrameworks プログラミング入門 P169
http://www.amazon.co.jp/gp/product/4861006708?ie=UTF8&tag=laxcomplex-22&linkCode=as2&camp=247&creative=1211&creativeASIN=4861006708
参考:http://wonderfl.net/code/2bfaa6e6b54bc46b3aa9b0210103f3812aa00376
@author Aquioux(Yoshida, Akio)
Get Adobe Flash player
by bradsedito 02 May 2012
    Embed
/**
 * Copyright bradsedito ( http://wonderfl.net/user/bradsedito )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/eev9
 */

// forked from Lawiz's forked from: [WebCam] 誰でもスーラ -Anyone Seurat-
// forked from Aquioux's [WebCam] 誰でもスーラ -Anyone Seurat-
package {
    import flash.display.Sprite;
    import net.hires.debug.Stats;
    [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")]
    /**
     * 誰でもスーラ -Anyone Seurat-
     * 点描派風ピクセレート・ウェブカム版
     * ネタ元:Beyond Interaction -メディアアートのための openFrameworks プログラミング入門 P169
     * http://www.amazon.co.jp/gp/product/4861006708?ie=UTF8&tag=laxcomplex-22&linkCode=as2&camp=247&creative=1211&creativeASIN=4861006708
     * 参考:http://wonderfl.net/code/2bfaa6e6b54bc46b3aa9b0210103f3812aa00376
     * @author Aquioux(Yoshida, Akio)
     */
    public class Main extends Sprite {
        
        public function Main():void {
            Wonderfl.capture_delay(20);
            
            // model
            try {
                var model:Model = new Model(stage);
            } catch (err:Error) {
                trace(err.message);
                return;
            }
            
            // view
            var view:View = new View(model);
            addChild(view);
            
            addChild(new Stats());
        }
    }
}


    import flash.display.BitmapData;
    import flash.display.Stage;
    import flash.events.ActivityEvent;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.geom.Matrix;
    import flash.media.Camera;
    import flash.media.Video;
    /**
     * Model
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Model extends EventDispatcher {
        // ---------- パブリックプロパティ ----------
        //
        // View へ渡すデータ
        public function get data():BitmapData { return _data; }
        private var _data:BitmapData;

        
        // ---------- ローカルプロパティ ----------
        //
        private var stage_:Stage;
        private var cameraWidth_:uint;
        private var cameraHeight_:uint;
        private var camera_:Camera;
        private var video_:Video;
        private var matrix_:Matrix;
        

        // ---------- パブリックメソッド ----------
        //
        /**
         * コンストラクタ
         * @param    stage    ステージ
         * @param    cw        カメラ幅(省略時はステージ幅)
         * @param    ch        カメラ高(省略時はステージ高)
         */
        public function Model(stage:Stage, cw:uint = 0, ch:uint = 0) {
            // 引数の処理
            stage_ = stage;
            var w:uint = stage_.stageWidth;
            var h:uint = stage_.stageHeight;
            cameraWidth_  = (cw == 0) ? w : cw;
            cameraHeight_ = (ch == 0) ? h : ch;

            // View へ渡すデータの生成
            _data = new BitmapData(w, h, false, 0x000000);
            
            // 鏡像になるよう、Matrix で左右反転
            var tx:uint = (w - cameraWidth_)  / 2 + cameraWidth_;
            var ty:uint = (h - cameraHeight_) / 2;
            matrix_ = new Matrix( -1, 0, 0, 1, tx, ty);
            
            // カメラ準備
            camera_ = Camera.getCamera();
            if (camera_) {
                // camera のセットアップ
                camera_.setMode(cameraWidth_, cameraHeight_, stage_.frameRate);
                // video のセットアップ
                video_ = new Video(cameraWidth_, cameraHeight_);
                video_.attachCamera(camera_);
                // カメラがアクティブになるまで待つ
                camera_.addEventListener(ActivityEvent.ACTIVITY, activeHandler);
            } else {
                throw new Error("カメラがありません。");
            }
        }
        
        
        // ---------- ローカルメソッド ----------
        //
        // ACTIVITY イベントハンドラ
        private function activeHandler(e:ActivityEvent):void {
            camera_.removeEventListener(ActivityEvent.ACTIVITY, arguments.callee);
            stage_.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        // ENTER_FRAME イベントハンドラ
        private function enterFrameHandler(event:Event):void {
            _data.draw(video_, matrix_);
            dispatchEvent(new Event(Event.CHANGE));
        }
    }


    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.filters.BitmapFilterQuality;
    import flash.filters.BlurFilter;
    /**
     * View
     * @author YOSHIDA, Akio (Aquioux)
     */
    class View extends Bitmap {
        // ---------- パブリックプロパティ ----------
        //
        // Model の参照
        public function set model(value:Model):void { _model = value; }
        private var _model:Model;
        
        // Controller の参照
        //public function set controller(value:Controller):void { _controller = value; }
        //private var _controller:Controller;
        
        
        // ---------- ローカルプロパティ ----------
        //
        // 各エフェクタ
        private var smooth:Smooth;        // 平滑化のためのエフェクタ
        //private var smooth2:Smooth;        // 最後にぼかすためのエフェクタ
        private var tone:HalftoneColor;    // ハーフトーン化
        

        // ---------- パブリックメソッド ----------
        //
        /**
         * コンストラクタ
         * @param    model    Model
         */
        public function View(model:Model) {
            _model = model;
            _model.addEventListener(Event.CHANGE, changeHandler);
            
            smooth = new Smooth();        // 平滑化
            smooth.strength = 2;
            tone = new HalftoneColor();    // ハーフトーン
            tone.size = 20;
            
            filters = [new BlurFilter(8, 8, BitmapFilterQuality.MEDIUM)];
        }
        

        // ---------- ローカルメソッド ----------
        //
        // Model から Event.CHANGE が発行されたときの処理
        private function changeHandler(e:Event):void {
            // Model からデータを受け取り、視覚化
            var bmd:BitmapData = _model.data;
            smooth.applyEffect(bmd);    // 平滑化
            tone.applyEffect(bmd);        // ハーフトーン
            bitmapData = bmd;
        }
    }


    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.geom.Rectangle;
    /**
     * ハーフトーン(カラー)
     * @author YOSHIDA, Akio (Aquioux)
     */
    class HalftoneColor implements IEffector {
        // ---------- パブリックプロパティ ----------
        //
        public function set size(value:uint):void {
            _size = value;

            wNum_ = Math.ceil(width_  / _size);    // width / _size が割り切れない場合は切り上げ
            hNum_ = Math.ceil(height_ / _size);    // height / _size が割り切れない場合は切り上げ
            
            if (blockBmd_) blockBmd_.dispose();
            blockBmd_ = new BitmapData(_size, _size);
            
            blockRect_.width = blockRect_.height = _size;
            
            blockPixels_ = _size * _size;
        }
        private var _size:uint = 40
        ;                // モザイクの1辺の長さ(縦横同じ長さとする)
        

        // ---------- ローカルプロパティ ----------
        //
        private var width_:Number;            // 対象幅
        private var height_:Number;            // 対象高

        private var wNum_:uint;                // 横方向のモザイク数
        private var hNum_:uint;                // 縦方向のモザイク数
        
        private var blockBmd_:BitmapData;    // モザイク1つ分の BitmapData
        private var blockRect_:Rectangle;// モザイク1つ分の Rectangle(モザイク領域読込時とトーン描画時で使い回す)
        private var blockPixels_:uint;        // モザイク1つ分の pixel 数
        
        // バッファ
        static private var rBmd_:BitmapData;    // for RED Channel
        static private var gBmd_:BitmapData;    // for GREEN Channel
        static private var bBmd_:BitmapData;    // for BLUE Channel
        static private var bufferBmds_:Array;

        static private var totalRect_:Rectangle;// 全体の Rectangle

        
        // ---------- パブリックメソッド ----------
        //
        /*
         * コンストラクタ
         */
        public function HalftoneColor(width:Number = 0.0, height:Number = 0.0) {
            width_  = width;    // 対象幅を待避
            height_ = height;    // 対象高を待避
            blockRect_ = new Rectangle();
            if (width_ != 0.0 && height_ != 0.0) init(width, height);
        }
        
        /*
         * 効果適用
         * @param    value    効果対象 BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            // 2回目以降
            if (rBmd_){
                rBmd_.fillRect(totalRect_, 0x00000000);
                gBmd_.fillRect(totalRect_, 0x00000000);
                bBmd_.fillRect(totalRect_, 0x00000000);
            }
            // 初回
            if (width_ == 0.0 || height_ == 0.0) init(value.width, value.height);

            var saveBmd:BitmapData = value.clone();    // カメラ画像を待避
            value.fillRect(value.rect, 0xFF000000);    // 塗りつぶす

            // モザイクブロックごとの走査
            value.lock();
            for (var i:int = 0; i < hNum_; i++) {
                for (var j:int = 0; j < wNum_; j++) {
                    var px:Number = j * _size;
                    var py:Number = i * _size;
                    // モザイク領域読込用としての blockRect_ 設定
                    blockRect_.x = px;
                    blockRect_.y = py;
                    blockRect_.width  = blockRect_.height = _size;
                    // モザイク領域を全体から切り取る
                    blockBmd_.copyPixels(saveBmd, blockRect_, EffectorUtils.ZERO_POINT);
                    // モザイク領域の各カラーチャンネルの平均輝度取得
                    var brightness:Vector.<uint> = getAverageBrightness(blockBmd_.histogram());
                    for (var k:int = 0; k < 3; k++) {
                        // 描画サイズの設定
                        var blockSize:Number = _size * (brightness[k] / 255) * 0.9;    // 90% 補正
                        // 描画開始位置オフセット計算
                        var offset:Number = (_size - blockSize) / 2;
                        // トーン描画用としての blockRect_ 設定
                        blockRect_.x = px + offset + Math.random() - 0.5;
                        blockRect_.y = py + offset + Math.random() - 0.5;
                        blockRect_.width = blockRect_.height = blockSize;
                        // バッファに描画
                        bufferBmds_[k].fillRect(blockRect_, 0xFFFFFFFF);
                    }
                }
            }
            value.copyChannel(rBmd_, totalRect_, EffectorUtils.ZERO_POINT, BitmapDataChannel.RED, BitmapDataChannel.RED);
            value.copyChannel(gBmd_, totalRect_, EffectorUtils.ZERO_POINT, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            value.copyChannel(bBmd_, totalRect_, EffectorUtils.ZERO_POINT, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            value.unlock();
            return value;
        }
        

        // ---------- ローカルメソッド ----------
        //
        // 初期化
        private function init(width:Number, height:Number):void {
            width_  = width;    // 対象幅を待避
            height_ = height;    // 対象高を待避
            size    = _size;    // _size の設定

            rBmd_ = new BitmapData(width_, height_, true, 0x00000000);
            gBmd_ = rBmd_.clone();
            bBmd_ = rBmd_.clone();
            bufferBmds_ = [rBmd_, gBmd_, bBmd_];
            totalRect_ = new Rectangle(0, 0, width_, height_);
        }

        // 平均輝度を求める
        private function getAverageBrightness(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];
            }
            var r:uint = rSum / blockPixels_ >> 0;
            var g:uint = gSum / blockPixels_ >> 0;
            var b:uint = bSum / blockPixels_ >> 0;
            
            return Vector.<uint>([r, g, b]);
        }
    }


    import flash.display.BitmapData;
    import flash.filters.BitmapFilterQuality;
    import flash.filters.BlurFilter;
    /**
     * BlurFilter による平滑化
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Smooth implements IEffector {
        // ---------- パブリックプロパティ ----------
        //
        /*
         * ぼかしの強さ
         * @param    value    数値
         */
        public function set strength(value:Number):void {
            blurFilter_.blurX = blurFilter_.blurY = value;
        }
        /*
         * ぼかしの質
         * @param    value    数値
         */
        public function set quality(value:int):void {
            blurFilter_.quality = value;
        }


        // ---------- ローカルプロパティ ----------
        //
        // ブラーフィルタ
        private var blurFilter_:BlurFilter;


        // ---------- パブリックメソッド ----------
        //
        /*
         * コンストラクタ
         */
        public function Smooth() {
            blurFilter_ = new BlurFilter(2, 2, BitmapFilterQuality.MEDIUM);
        }
        
        /*
         * 効果適用
         * @param    value    効果対象 BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            value.applyFilter(value, value.rect, EffectorUtils.ZERO_POINT, blurFilter_);
            return value;
        }
    }


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


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