Ahmed Nuaman


builder of internets ~ developer of dreams ~ tamer of Dachshunds

Capturing A Webcam Snapshot And Posting To The Server

So a while back I did some code for a company (who shall remain nameless) who screwed me over. So in the end I thought I’d swallow my pride and make the code open source.

At the moment I’ve only added the AS3 part, I’ve yet to add a server side part, I’ll probably do it in PHP and/or Python, but the logic will remain the same in whatever language you use.

So, without further ado, here is the AS3:

/**
 * @author          Ahmed Nuaman (http://www.ahmednuaman.com)
 * @langversion     3
 *
 * This work is licenced under the Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.
 * To view a copy of this licence, visit http://creativecommons.org/licenses/by-sa/2.0/uk/ or send a letter
 * to Creative Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.
*/

package
{
    import com.adobe.images.JPGEncoder;
   
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLRequestHeader;
    import flash.net.URLRequestMethod;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
   
    [SWF( backgroundColor=0xFFFFFF, frameRate=30, height=300, width=320 )]
   
    public class App extends Sprite
    {
        // you won't need to touch these
        public static const CAMERA_BANDWIDTH:Number             = 0;
        public static const CAMERA_QUALITY:Number               = 90;
       
        // set the height and width of the camera below
        public static const CAMERA_HEIGHT:Number                = 240;
        public static const CAMERA_WIDTH:Number                 = 320;
       
        // set the URL you want the app to post the bytearray to
        public static const POST_URL:String                     = '';
       
        private var button:Sprite;
        private var camera:Camera;
        private var preview:Sprite;
        private var video:Video;
       
        public function App()
        {
            // we check to see if the app and stage are ready
            loaderInfo.addEventListener( Event.INIT, handleInit );
        }
       
        private function handleInit(e:Event):void
        {
            loaderInfo.removeEventListener( Event.INIT, handleInit );
           
            // here we add the camera
            getCamera();
           
            // here we add the button to capture and submit the image
            addButton();
        }
       
        private function getCamera():void
        {
            var index:int = 0;
           
            // here we cycle through the user's cameras so that they don't have to select it
            // this is in case they are video editors, for example, as they may have lots of
            // cameras attached to their computer
            for ( var i:int = 0; i < Camera.names.length; i++ )
            {
                if ( Camera.names[ i ] == 'USB Video Class Video' )
                {
                    index = i;
                }
            }
           
            // so we set the selected camera here
            camera = Camera.getCamera( index.toString() );
           
           
            // we set it up
            camera.setMode( CAMERA_WIDTH, CAMERA_HEIGHT, 20, true );
            camera.setQuality( CAMERA_BANDWIDTH, CAMERA_QUALITY );
           
            // we create a video display object for the camera
            video = new Video( CAMERA_WIDTH, CAMERA_HEIGHT );
           
            video.smoothing = true;
           
            // attach the camera to the video display object
            video.attachCamera( camera );
           
           
            // add the video display object to the stage so the user can see it
            addChild( video );
        }
       
        private function addButton():void
        {
            // here we just set up the button
            var field:TextField = new TextField();
            var format:TextFormat = new TextFormat( 'Arial', 10, 0xFFFFFF );
           
            field.autoSize = TextFieldAutoSize.LEFT;
            field.text = 'Capture!';
           
            field.setTextFormat( format );
           
            button = new Sprite();
           
            button.graphics.beginFill( 0x333333 );
            button.graphics.drawRoundRect( 0, 0, 60, 20, 3, 3 );
            button.graphics.endFill();
           
            button.addChild( field );
           
            field.x = ( button.width - field.width ) / 2;
            field.y = ( button.height - field.height ) / 2;
           
            addChild( button );
           
            button.buttonMode = true;
            button.mouseChildren = false;
            button.x = ( stage.stageWidth - button.width ) / 2;
            button.y = stage.stageHeight - button.height - 20;
           
            // and this is the listener that links the button to the function we'll
            // use to send the image
            button.addEventListener( MouseEvent.CLICK, handleButtonClick );
        }
       
        private function handleButtonClick(e:MouseEvent):void
        {
            // this is where the magic happens
            // we set up the request and loader
            var request:URLRequest = new URLRequest();
            var loader:URLLoader = new URLLoader();
           
            // we create the encoder
            var encoder:JPGEncoder = new JPGEncoder( CAMERA_QUALITY );
           
            // we set up the snapshot
            var shot:BitmapData = new BitmapData( CAMERA_WIDTH, CAMERA_HEIGHT );
           
           
            // we then get the snapshot
            shot.draw( video );
           
            // encode it and build the request
            request.data    = encoder.encode( shot );
            request.method  = URLRequestMethod.POST;
            request.url     = POST_URL + loaderInfo.parameters.v;
           
            // not forgetting to add the headers
            request.requestHeaders.push( new URLRequestHeader( 'Content-type', 'application/octet-stream' ) );
           
            loader.addEventListener( Event.COMPLETE, handleComplete );
           
            // and off the request goes!
            loader.load( request );
        }
       
        private function handleComplete(e:Event):void
        {
            // check if the preview container exists
            if ( preview )
            {
                // if it does, clear it
                preview.removeChildAt( 0 );
            }
            else
            {
                // if it doesn't, create it
                preview = new Sprite();
               
                addChild( preview );
            }
           
            // build the loader and request
            var loader:Loader       = new Loader();
            var request:URLRequest  = new URLRequest( e.target.data );
           
            // add listener
            loader.contentLoaderInfo.addEventListener( Event.COMPLETE, handlePreviewComplete );
           
            // load
            loader.load( request );
        }
       
        private function handlePreviewComplete(e:Event):void
        {
            // get the loader
            var image:Loader    = e.target.loader as Loader;
           
            // adjust its size         
            image.height        = CAMERA_HEIGHT / 4;
            image.width         = CAMERA_WIDTH / 4;
           
            // add it to the stage
            preview.addChild( image );
        }
    }
}

All you need to do is change the POST_URL to a server side script that’ll handle the bitmap stream coming down (basically the $_POST body). Also, I’ve put the code up on Github for all you to have a play with! Enjoy! :D

Where have comments gone?

Good question my old fruity. I'm now sticking any post discussions on Google+. Why? Well simply it's better. WordPress's comment system isn't very elegant and nor are ones like Disqus or Livefyre, so to save hassle I've just shipped them off to a social network, like a real boss.

Search

My social skills

Latest blog posts

  • Loading posts...

Subscribe in a reader

Latest tweets

  • Loading tweets...