flash on 2011-11-23

by sasa
< 背景画像
< ビデオの幅
< ビデオの高さ
< 画面の幅
< 画面の高さ
< 背景画像
ボタン追加
Chromakey ON ボタン処理
Chromakey OFF ボタン処理
描画処理
画面の真ん中の色を色調整用に出力
マスクの作成
var maskBitmap:BitmapData = bdTmp.clone();    ///< こっちだとなんかダメ
青系の色を透過色にする(ここの色の値を調整するとクロマキーで抜ける色が変わる)
< 赤、緑がこの値以上だったら透過色ではない
< 青がこの値以上でないと透過色ではない
まず赤、緑成分が一定値以上のところをMASKFLAG_COLORで塗りつぶす
次に青成分が、一定値以下のところをMASKFLAG_COLORで塗りつぶす
MASKFLAG_COLORで塗られてないところをalphaで塗りつぶし(残ったところはかなり青いはず)
背景描画を描画
マスキングして、WEBカメラ画像の描画
< カメラ
< ビデオ
< 外枠用
< BMPデータ
< テンポラリビットマップデータ
< ラベル

コンストラクタ
@param screenWidth SWFの幅
@param screenHeight SWFの高さ
@param videoWidth ビデオの幅
@param videoHeight ビデオの高さ

filterの作成
背景色用オブジェクト作成
BMPデータの作成
ラベル
カメラの取得
イベントリスナーの追加
ビデオの生成
メインループ追加
状態イベントの処理
メインループ
カメラがアクセス禁止されている
bdTmpにビデオデータを転送            
画面描画
背景色の描画

この関数がoverrideされ、カメラの描画処理を決定する

指定されているURLのウェブサイトを開く
@param openURL 開くURL

handle error here
ボタン
♥0 | Line 207 | Modified 2011-11-23 16:44:06 | MIT License
play

ActionScript3 source code

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

package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;

    [SWF(width="360", height="320", backgroundColor="#ffffff", frameRate="15")]

    public class ChromakeyCamera extends CameraFramework
    {
        [Embed(source='backGround.jpg')]
        private var BackGround:Class;       ///< 背景画像

        public static const
            VIDEO_WIDTH:int = 320,          ///< ビデオの幅
            VIDEO_HEIGHT:int = 240,         ///< ビデオの高さ
            SCREEN_WIDTH:int = 360,         ///< 画面の幅
            SCREEN_HEIGHT:int = 320;        ///< 画面の高さ

        private var backGround:BitmapData = null;       ///< 背景画像
        private var chromakeyOn:Boolean = true;

        public function ChromakeyCamera()
        {
            super( SCREEN_WIDTH, SCREEN_HEIGHT, VIDEO_WIDTH, VIDEO_HEIGHT );

            var bmp:Bitmap = new BackGround();
            backGround = bmp.bitmapData;

            label.text = "Chromakey Camera";
            drawBgColor(0xD78500);

            // ボタン追加
            var buttonY:int = 10, buttonW:int = 140;
            var chromakeyOnButton:TextButton = new TextButton(buttonW, 20, "ChromaKey ON");
            chromakeyOnButton.x = 10;
            chromakeyOnButton.y = buttonY;
            addChild(chromakeyOnButton);
            chromakeyOnButton.addEventListener( MouseEvent.CLICK, chromakeyOnButtonClick );

            var chromakeyOffButton:TextButton = new TextButton(buttonW, 20, "ChromaKey OFF");
            chromakeyOffButton.x = chromakeyOnButton.x + chromakeyOnButton.width + 10;
            chromakeyOffButton.y = buttonY;
            addChild(chromakeyOffButton);
            chromakeyOffButton.addEventListener( MouseEvent.CLICK, chromakeyOffButtonClick );
        }

        /// Chromakey ON ボタン処理
        private function chromakeyOnButtonClick(event:MouseEvent):void {
            chromakeyOn = true;
        }

        /// Chromakey OFF ボタン処理
        private function chromakeyOffButtonClick(event:MouseEvent):void {
            chromakeyOn = false;
        }

        /// 描画処理
        public override function draw():void {

            /// 画面の真ん中の色を色調整用に出力
            trace( "COLOR:" + bdTmp.getPixel32(VIDEO_WIDTH/2,VIDEO_HEIGHT/2).toString(16) );

            if( chromakeyOn == false ){
                bd.draw(bdTmp);
                return;
            }

            /// マスクの作成
            //var maskBitmap:BitmapData = bdTmp.clone();    ///< こっちだとなんかダメ
            var MASKFLAG_COLOR:uint = 0xFFFF0000;
            var maskBitmap:BitmapData = new BitmapData(bdTmp.width, bdTmp.height);
            maskBitmap.draw(bdTmp);

            /// 青系の色を透過色にする(ここの色の値を調整するとクロマキーで抜ける色が変わる)
            var THRESHOLD_RG_COLOR:uint = 0x444400;     ///< 赤、緑がこの値以上だったら透過色ではない
            var THRESHOLD_BLUE_COLOR:uint = 0x000060;   ///< 青がこの値以上でないと透過色ではない

            // まず赤、緑成分が一定値以上のところをMASKFLAG_COLORで塗りつぶす
            maskBitmap.threshold(maskBitmap, maskBitmap.rect, new Point(), ">", THRESHOLD_RG_COLOR, MASKFLAG_COLOR, 0x00ffff00 );
            // 次に青成分が、一定値以下のところをMASKFLAG_COLORで塗りつぶす
            maskBitmap.threshold(maskBitmap, maskBitmap.rect, new Point(), "<", THRESHOLD_BLUE_COLOR, MASKFLAG_COLOR, 0x000000ff );
            // MASKFLAG_COLORで塗られてないところをalphaで塗りつぶし(残ったところはかなり青いはず)
            maskBitmap.threshold(maskBitmap, maskBitmap.rect, new Point(), "!=", MASKFLAG_COLOR, 0x00000000);

            /// 背景描画を描画
            bd.draw(backGround);

            /// マスキングして、WEBカメラ画像の描画
            bd.copyPixels( bdTmp, bdTmp.rect, new Point(), maskBitmap, new Point(), true);

        }

    }
}

    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.text.*;
    import flash.geom.*
    import flash.errors.*;
    import flash.filters.*;
    import flash.utils.*;
    import flash.net.*;

    public class CameraFramework extends Sprite
    {
        private var camera:Camera = null;               ///< カメラ
        public var video:Video = null;                  ///< ビデオ
        public var bgShape:Shape = new Shape();         ///< 外枠用
        public var bd:BitmapData;                       ///< BMPデータ
        public var bdTmp:BitmapData;                    ///< テンポラリビットマップデータ
        public var label:TextField = new TextField();   ///< ラベル

        /**
         * コンストラクタ
         * @param screenWidth SWFの幅
         * @param screenHeight SWFの高さ
         * @param videoWidth ビデオの幅
         * @param videoHeight ビデオの高さ
         */
        public function CameraFramework( screenWidth:int, screenHeight:int, videoWidth:int, videoHeight:int )
        {
            // filterの作成
            var filter:Array = new Array;
            filter.push( new DropShadowFilter() );

            // 背景色用オブジェクト作成
            addChild(bgShape);
            drawBgColor(0x333333);

            // BMPデータの作成
            var bmp:Bitmap
            bd = new BitmapData( videoWidth, videoHeight, false, 0xffffff);
            bmp = new Bitmap(bd);
            bmp.filters = filter;
            bmp.x = (screenWidth - videoWidth)/2;
            bmp.y = (screenHeight - videoHeight)/2;
            addChild(bmp);

            bdTmp = new BitmapData( videoWidth, videoHeight, false, 0xffffff);

            //ラベル
            label.autoSize=TextFieldAutoSize.LEFT;
            label.text = "WebCamera Framework";
            label.filters = filter;
            label.textColor = 0xffffff;
            label.x = 2;
            label.y = screenHeight - label.textHeight - 10;
            addChild(label);

            //カメラの取得
            camera=Camera.getCamera();

            if (camera!=null) {
                //イベントリスナーの追加
                camera.addEventListener(StatusEvent.STATUS,statusHandler);
                //ビデオの生成
                video = new Video( videoWidth, videoHeight );
                video.attachCamera(camera);
            } else {
                label.text="カメラを利用できません";
            }

            // メインループ追加
            addEventListener(Event.ENTER_FRAME, tick);
        }

        /// 状態イベントの処理
        private function statusHandler(evt:StatusEvent):void {
            if (camera.muted){
                label.text="カメラを利用できません";
            }
        }

        /// メインループ
        private function tick( event:Event ):void
        {
            if(video == null || camera == null){
                return;
            }

            if( camera.muted == true ){
                // カメラがアクセス禁止されている
                return;
            }

            // bdTmpにビデオデータを転送            
            bdTmp.draw(video);

            // 画面描画
            draw();
        }

        /// 背景色の描画
        public function drawBgColor(color:uint):void {
            bgShape.graphics.lineStyle(0,color);
            bgShape.graphics.beginFill(color);
            bgShape.graphics.drawRect(0,0,360,320);
            bgShape.graphics.endFill();
        }

        /**
         * この関数がoverrideされ、カメラの描画処理を決定する
         */
        public function draw():void {
            for( var y:int = 0; y < bdTmp.height; ++y ){
                for( var x:int = 0; x < bdTmp.width; ++x ){
                    var color:uint = bdTmp.getPixel(x , y);
                    bd.setPixel(x, y, color);
                }
            }
        }

        /**
         * 指定されているURLのウェブサイトを開く
         * @param openURL 開くURL
         */
        private function openWebsite(openURL:String):void {
            var variables:URLVariables = new URLVariables();
            var request:URLRequest = new URLRequest(openURL);

            try {
                navigateToURL(request);
            }
            catch (e:Error) {
                // handle error here
            }
        }

    }
    
    import flash.display.*;
    import flash.filters.*;
    import flash.text.*;

    /// ボタン
    public class TextButton extends SimpleButton {

        /**
         * コンストラクタ
         * @param w 幅
         * @param h 高さ
         * @param text ボタンに表示する文字列
         */
        public function TextButton( w:uint, h:uint, text:String ) {

            var ew:uint = 15;
            downState = makeRoundRect(w, h, ew, 0x006600, text);
            overState = makeRoundRect(w, h, ew, 0x00ff00, text);
            upState = makeRoundRect(w, h, ew, 0x777777, text);

            var filter:Array = new Array;
            filter.push( new DropShadowFilter() );
            this.filters = filter;

            //当たり判定
            hitTestState = upState;

            //ハンドアイコン 
            useHandCursor = true;

        }

        /**
         * テキストフォーマットの生成
         * @param size サイズ
         * @param color 色
         */
        public static function makeTextFormat(size:uint,color:uint):TextFormat {
            var format:TextFormat=new TextFormat();
            format.font ="_等幅";
            format.size =size;
            format.color=color;
            format.bold =true;
            return format;
        }

        /** 
         * 一定高さ以下にフォントサイズを調整。height以下の高さに
         */
        public static function setFontHeight(label:TextField,format:TextFormat,height:uint):void {
            var i:uint;
            var lastSize:uint = 1;

            for(i = lastSize;; i++ ){
                format.size=i;
                label.setTextFormat(format);
                if (label.textHeight >= height){
                    break;
                }
                lastSize = i;
            }

            format.size = lastSize;
            label.setTextFormat(format);
        }

        /**
         * 角円矩形の作成
         * @param w 幅
         * @param h 高さ
         * @param ew 角の丸まり
         * @param color 色
         */
        private function makeRoundRect(w:uint,h:uint,ew:uint,color:uint,text:String):Sprite {
            var rrect:Sprite=new Sprite();
            rrect.graphics.beginFill(color);         //塗り潰し色
            rrect.graphics.drawRoundRect(0,0,w,h,ew);//XY座標,幅,高さ,角丸幅
            rrect.graphics.endFill();                //塗り潰し終了
            rrect.alpha = 0.8;

            var textHeight:uint = h/4*3;
            var textField:TextField=new TextField();
            textField.text = text;
            textField.y = (h - textHeight)/2;
            textField.width = w;
            textField.height = textHeight;
            textField.selectable = false;
            textField.mouseEnabled = false;
            textField.autoSize = TextFieldAutoSize.CENTER;

            var format:TextFormat = makeTextFormat(12, 0xffffff);
            setFontHeight(textField, format, textHeight);
            textField.setTextFormat(format);

            rrect.addChild(textField);
            return rrect;
        }

    }