Sunday, November 21st, 2010
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!