Home > Tutorial > Access Webcam with Flash

Access Webcam with Flash

February 7th, 2009 kmussel

I wanted a user to be able to upload pictures via their webcam. This post will show how to make a flash application using Flash 8 and actionscript 2 to have a website access a users webcam and take a picture and save it.

First off we need to import the following files:


 //This will allow us to create a photo
import flash.display.BitmapData;
// This is used to mirror the look of the webcam
import flash.geom.Matrix;
 //Used to interact with javascript
import flash.external.ExternalInterface;



This code is used to actually display the webcam on the screen except we’re setting the video visible to false.


video_vobj._visible = false;
var cam:Camera = Camera.get();
cam.setQuality(0,30);
cam.setMode(300, 400, 28);



Occasionally when you reload the page the webcam displays a scrambled image or the last frame displayed. I rather not see anything if the camera isn’t ready which is why we set the video visible to false to begin. This next bit is a little hack to fix that problem.


var firstone:Boolean = true;
cam.onActivity = function(isActive:Boolean) {
  if(firstone){
  //clears the video screen so it won't display the scrambled screen or frozen frame.
	video_vobj.clear();
        firstone = false;
        video_vobj._visible = true;
  }
};



The position of the video.


var videoX:Number = video_vobj._x;
var videoY:Number = video_vobj._y;
var videoW:Number = video_vobj._width;
var videoH:Number = video_vobj._height;



In order for the website to access the webcam, a user must give the website permission.

If muted is true it means that the website currently doesn’t have access. By default flash will popup with a allow/deny dialog box but I prefer to display the settings dialog box. This is because the settings dialog box allows you to check a remember box so the website will always have access to the webcam unless you go into the settings and change it again. It also has a few other options like choosing a different webcam.


if(cam.muted == true){
      //Shows the setting dialog box with which tab to display passed to it.
	System.showSettings(0);
}else{
	video_vobj.attachVideo(cam);
	createbutton();
}



This is a camera event that is triggered when access to the webcam has been granted or denied.

cam.onStatus = function(infoObj:Object) {
    switch (infoObj.code) {
    case 'Camera.Muted' :
    break;
    case 'Camera.Unmuted' :
	  video_vobj.attachVideo(cam);
	  createbutton();
    break;
    }
}



First we’ll create a movie clip that will hold the button to take the picture.


var root:MovieClip = this;
root._x = 50;
root.createEmptyMovieClip("take", root.getNextHighestDepth());



I wanted to create a button that a user could click to take a picture. This could have just as easily been accomplished by adding a button in flash but I wanted to try it this way.


function createbutton(){
	take._x = 10;
	take._y = 435;
	var fillType:String = "linear";
	var colors:Array = [0xFAD4DB, 0xEC748B, 0xC13A59, 0xA81230];
	var alphas:Array = [100, 100, 100, 100];
	var ratios:Array = [0, 126, 127, 255];
	var matrix:Object = {matrixType:"box", x:0, y:0, w:80, h:30,
        r:90/180*Math.PI};
	take.createEmptyMovieClip("takebtn", reset.getNextHighestDepth());
	take.takebtn.lineStyle(0, 0x820F26, 60, true, "none", "square", "round");
	take.takebtn.beginGradientFill(fillType, colors, alphas, ratios, matrix);
	take.takebtn.lineTo(120, 0);
	take.takebtn.lineTo(120, 30);
	take.takebtn.lineTo(0, 30);
	take.takebtn.lineTo(0, 0);
	take.takebtn.endFill();
	take.createTextField("labelText", take.getNextHighestDepth(), 0, 5,
         take._width, 24);
	take.labelText.text = "Take Picture";
}



Takes the inverse of the xscale in order to mirror the image.


video_vobj._x = video_vobj._width;
video_vobj._xscale = -video_vobj._xscale;



When you click the Take Picture button it triggers an event that will store the image that is currently on the screen
into this bitmap.


var screenS:BitmapData = new BitmapData(video_vobj._width, video_vobj._height,
                                       true, 0xff0000);



This function is called to reset everything to how it was at the start.


function resetflash(){
	root.holder.removeMovieClip();
	root.myButton1.removeMovieClip();
	root.reset.removeMovieClip();
	if(root.loader)
		root.loader.removeMovieClip();
}



This is the code to actually creates the image. The screenS.draw function takes the video and matrix to draw a mirrored image.


take.onRelease = function() {
	var mymatrix:Matrix = new Matrix();
	if(mymatrix.a>0){
		mymatrix.a=-1.875*mymatrix.a;
		mymatrix.d= 3.333*mymatrix.d;
		mymatrix.tx= video_vobj._width;
	}
       screenS.draw(video_vobj, mymatrix);



I create a empty movie clip to hold and display the image. This makes it easy to remove the image by simply removing the movie clip. When I create one I pass the name and the depth. The root.getNextHighestDepth() makes sure that flash renders the movie clip in front of all the others.


root.createEmptyMovieClip("holder", root.getNextHighestDepth());
holder.attachBitmap(screenS, 1);
holder._x = videoX;
holder._y = videoY;
holder._width = videoW;
holder._height = videoH;



Here I create another button to reset everything to the start positions.


root.createEmptyMovieClip("reset", root.getNextHighestDepth());
reset._x = 10;
reset._y = 435;
var fillType:String = "linear";
var colors:Array = [0xFAD4DB, 0xEC748B, 0xC13A59, 0xA81230];
var alphas:Array = [100, 100, 100, 100];
var ratios:Array = [0, 126, 127, 255];
var matrix:Object = {matrixType:"box", x:0, y:0, w:80, h:30, r:90/180*Math.PI};
reset.createEmptyMovieClip("resetbtn", reset.getNextHighestDepth());
reset.resetbtn.lineStyle(0, 0x820F26, 60, true, "none", "square", "round");
reset.resetbtn.beginGradientFill(fillType, colors, alphas, ratios, matrix);
reset.resetbtn.lineTo(120, 0);
reset.resetbtn.lineTo(120, 30);
reset.resetbtn.lineTo(0, 30);
reset.resetbtn.lineTo(0, 0);
reset.resetbtn.endFill();
reset.createTextField("labelText", reset.getNextHighestDepth(), 0, 5,
   reset._width, 24);
reset.labelText.text = "Discard";



Here I create another button in order to save the image.


root.createEmptyMovieClip("myButton1", root.getNextHighestDepth());
myButton1._x = 150;
myButton1._y = 435;
var fillType:String = "linear";
var colors:Array = [0xFAD4DB, 0xEC748B, 0xC13A59, 0xA81230];
var alphas:Array = [100, 100, 100, 100];
var ratios:Array = [0, 126, 127, 255];
var matrix:Object = {matrixType:"box", x:0, y:0, w:80, h:30, r:90/180*Math.PI};
myButton1.createEmptyMovieClip("buttonBkg", myButton1.getNextHighestDepth());
myButton1.buttonBkg.lineStyle(0, 0x820F26, 60, true, "none",
   "square", "round");
myButton1.buttonBkg.beginGradientFill(fillType, colors, alphas,
   ratios, matrix);
myButton1.buttonBkg.lineTo(120, 0);
myButton1.buttonBkg.lineTo(120, 30);
myButton1.buttonBkg.lineTo(0, 30);
myButton1.buttonBkg.lineTo(0, 0);
myButton1.buttonBkg.endFill();
myButton1.createTextField("labelText", myButton1.getNextHighestDepth(),
  0, 5, myButton1._width, 24);
myButton1.labelText.text = "Save Image";

reset.onRelease = resetflash;



This is the event that will trigger the image to begin saving. I first create a movie clip to display a red film over the picture and text to display the progress of the picture. It then creates a SaveImage object. This object is defined in SaveImage.as which is a file you’ll have to create.


myButton1.onRelease = function(){
		tbo.text= screenS.width;
		root.createEmptyMovieClip("loader", root.getNextHighestDepth());
		loader._x = 0;
		loader._y = 0;
		loader.beginFill(0xFF0000, 50);
		loader.lineTo(300, 0);
		loader.lineTo(300, 400);
		loader.lineTo(0, 400);
		loader.lineTo(0, 400);
		loader.endFill();

		loader.createTextField("my_txt", 1, 0, 150, 300, 100);
		var my_fmt:TextFormat = new TextFormat();
		my_fmt.color = 0xFFFFFF;
		my_fmt.align="center";
		loader.my_txt.text = "Progress";
		loader.my_txt.setTextFormat(my_fmt);

		var si:SaveImage = new SaveImage();
		si.addListener( listener ); // assign a listener
		si.print(root, 0, 0, video_vobj._width, video_vobj._height) // copy the root
	}

};



I create a listener object that I added to si (SaveImage object). This is used to view the progress of the picture being saved and also when it is completed.


var listener:Object = new Object();

listener.onProgress = function(target:MovieClip, loaded:Number, total:Number){
var perc = Math.round((loaded/total)*100)
	var my_fmt:TextFormat = new TextFormat();
	my_fmt.color = 0xFFFFFF;
	my_fmt.align="center";
       loader.my_txt.text = "computing "+perc+"%";
	loader.my_txt.setTextFormat(my_fmt);
}



When the image is finished copying the data it sends it to some server file for processing via the sendAndLoad function. It then takes whatever was returned from the file and stores it in result_lv. When data is put into that LoadVars object an event onData is triggered. The src variable is what is returned and in this case is the name of the image I created. I then call my javascript function with the ExternalInterface.call which will display the image.


listener.onComplete = function(target:MovieClip, load_var:LoadVars){
	var result_lv:LoadVars = new LoadVars();
       result_lv.onData = function(src:String) {
		var retText = src;
		resetflash();
		ExternalInterface.call("showimg", retText);
    };
    load_var.sendAndLoad("yourfile.php", result_lv, "POST");
}



This next part is to make the SaveImage.as file. Everthing will be in class SaveImage. You can’t have more than one class in a .as file. The first part is to define some variables.


 class SaveImage {
    public var addListener:Function
    public var broadcastMessage:Function
    private var id:   Number;
    public  var record:LoadVars;



This function initializes the object and makes it an event broadcaster. This allows us to create custom event handling mechanisms. The listener object we added earlier will now receive notification anytime we call the broadcastMessage() method.


    function SaveImage(){
        AsBroadcaster.initialize( this );
    }



This is the function we called to begin copying the image data. We store it in the LoadVars object “record”. Then we call the setInterval function that calls copysource.


    public function print(mc:MovieClip, x:Number, y:Number, w:Number, h:Number){
        if(x == undefined) x = 0;
        if(y == undefined) y = 0;
        if(w == undefined) w = mc._width;
        if(h == undefined) h = mc._height;
        record = new LoadVars();
        record.width  = w
        record.height = h
        record.cols   = 0
        record.rows   = 0
        id = setInterval(copysource, 5, this, _root.video_vobj, _root.screenS);
    }



This function is the one that is actually copying all the image data pixel by pixel. Instead of looping through all of it at once I do it row by row by using the setInterval function. I do this so I can show the progress which is displayed when I call broadcastMessage(“onProgress”). After it is completed I call the clearInterval(this.id) so it wont call the funtion anymore.


    private function copysource(scope, movie, bit){
        var pixel:Number
        var str_pixel:String
        scope.record["px" + scope.record.rows] = new Array();
        for(var a = 0; a < bit.width; a++){
            pixel     = bit.getPixel(a, scope.record.rows)
            str_pixel = pixel.toString(16)
            if(pixel == 0xFFFFFF) str_pixel = "";   // don't send blank pixel
            scope.record["px" + scope.record.rows].push(str_pixel)
        }

        scope.broadcastMessage("onProgress", movie, scope.record.rows, bit.height)
        scope.record.rows += 1
        if(scope.record.rows >= bit.height){
            clearInterval(scope.id)
            scope.broadcastMessage("onComplete", movie, scope.record)
        }
    }
}



Here is the php code I use to process the post variables.

View PHP code


View All Flash Code

View Example


Here is the .fla and .as files

Flash Files

Categories: Tutorial Tags: ,
  1. Darren
    February 21st, 2009 at 11:10 | #1

    Hi this is wonderful, but Im not an expert in flash and am getting slightly confused. is there any chance you could email me all the files, or give me a detailed breakdown of what you actually need for this to work?

    Thanks

  2. Darren
    February 21st, 2009 at 11:41 | #2

    Darren :
    Hi this is wonderful, but Im not an expert in flash and am getting slightly confused. is there any chance you could email me all the files, or give me a detailed breakdown of what you actually need for this to work? Can you upload the source files by any chace please?
    Thanks

  3. Dan
    February 23rd, 2009 at 11:38 | #3

    Hey this is soooo cool. Is there a .fla available to download as all that code difficult to know where to place it within a flash file!

    Cheers and keep up the good work!!!

  4. kmussel
    February 23rd, 2009 at 18:05 | #4

    @Dan
    I posted a link to download the flash files at the end of the article.

  5. Dan
    February 27th, 2009 at 09:56 | #5

    Help i cant get the saved file to appear anywhere!

    Where do i save the image file? You have saved it in:

    load_var.sendAndLoad(“yourfile.php”, result_lv, “POST”);

    So do i just create a php file named yourfile.php and the image will appear here? Or do i need to have some code in the yourphp.php file? I so what code!?

    Thanks Again for your help!

  6. kmussel
    February 28th, 2009 at 12:30 | #6

    @Dan
    Yes create the php file which is used to process the post variables coming from flash. At the bottom of the tutorial a version of the php code I used is posted. You’ll need to copy that into your php file. This creates a file called name.jpg into the images folder. It then returns the name of the image to flash which you can then pass to javascript to display the picture without reloading the page. You’ll probably want the image name to be unique instead of “name” otherwise it will overwrite the previous image each time.

  7. Dan
    March 2nd, 2009 at 09:38 | #7

    I still cant manage to get flash to display the captured/saved image. I have copied the php code in to a file named yourfile.php, but what do you mean when you say: “This creates a file called name.jpg into the images folder. ” Where is the images folder? Do I need to create a new folder? Im just trying to get this working in flash at the moment.

    Thanks Again for your help!

  8. Veeru
    March 10th, 2009 at 01:44 | #8

    Hi there,
    I think the links for the example and to download the files is dead – i would really love to learn this and get this working! can you please re-up the links?

    Thanks
    Vru

    • kmussel
      March 10th, 2009 at 11:16 | #9

      Sorry about that, its back now.

  9. Silva
    March 16th, 2009 at 17:45 | #10

    Hi m8s.

    Can anyone help me? I’m completly screwed. I need to make a button activates through motion in webcam and that button has to call a music but i have no idea how. It’s for a project that was asked at school even though we dont have ANY formation in Flash…OMG…please help if u can.
    My e-mail is sr_gasoil@ol.pt

  10. kmussel
    March 17th, 2009 at 14:41 | #11

    @Silva
    The cam.onActivity = function(isActive:Boolean) {}; is what monitors if there is motion or not. So inside that is where you need to call your music.

  11. Daniel
    March 21st, 2009 at 09:29 | #12

    Figured it out! Was my (stupid) mistake – sorry. BRILLIANT CODE. Thank you, Kevin.
    I will send you a link of the site I will be using your code. Thanks again!

    Cheers
    Daniel

  12. Bobby
    March 22nd, 2009 at 06:53 | #13

    Can’t seem to get the unique naming php code working? What do I need to add within the php script to make him save the images with unique names? btw, great script!!!

  13. kmussel
    March 22nd, 2009 at 14:36 | #14

    @Bobby
    just come up with a unique name based on time() or if you’re storing it in a database you could base it on the id.

  14. March 26th, 2009 at 03:26 | #15

    hi, is very nice by why is the video image flip(ed) horizontal? left side is right and right side is left.
    What I can do it?

  15. Daniel
    March 26th, 2009 at 07:22 | #16

    Hi Kevin,
    the link to the site is http://5050box.com/hands.

    Thanks again, your code saved me a few hours! ;)

    Cheers
    Daniel

  16. Bobby
    March 27th, 2009 at 10:05 | #17

    Any idea why this doesn’t work in the PHP:

    $filename = “name.jpg”
    $fp = fopen(“images/$filename”, “w”);

    It doesn’t seem to save anything.

  17. kmussel
    March 27th, 2009 at 10:14 | #18

    @Bobby
    Well that is just going to open up a file for writing. You then need to
    call this function “fwrite($fp, $binary_data)” and then close it with “close($fp)”

  18. kmussel
    March 27th, 2009 at 10:15 | #19

    @aleko205
    i did it to see a mirrored image. if you dont want it mirrored you don’t need to take the inverse of the xscale. Also, take out the “if” statement dealing with the Matrix class inside the “take.onRelease” function.

  19. Bobby
    March 27th, 2009 at 10:35 | #20

    Tnx, but I already did that. I basically added that part of the script to your php. This is the last part:

    $filename = “name.jpg”
    $fp = fopen(“images/$filename”, “w”);
    ob_start();
    imagejpeg($img, “”, 90);
    $img = ob_get_contents();
    ob_end_clean();
    fwrite($fp, $img);
    fclose($fp)
    exit;

    Yet… still not working. Am I missing a small detail?

  20. kmussel
    March 27th, 2009 at 10:40 | #21

    @Bobby
    well if it’s not event creating a file then fopen is failing so I would check your folder permissions.

  21. April 21st, 2009 at 21:04 | #22

    i created a unique filename by adding time() to the filename…. how do i pass this unique filename to flash, so i can use loadmovie to import the jpg? thanks!

    heres the php
    $fp = fopen(“images/name”.time().”.jpg”, “w”);
    ob_start();
    imagejpeg($img, “”, 90);
    $img = ob_get_contents();
    ob_end_clean();
    fwrite($fp, $img);
    $my_string =
    echo “name”.time().”.jpg”;
    exit;
    ?>

  22. kmussel
    April 22nd, 2009 at 09:11 | #23

    @kev
    in the listener.onComplete event in result_lv.onData the ‘src’ in this case would be the name of the file. whatever you echo out in the file will be returned in this variable.

  1. February 8th, 2009 at 17:30 | #1
  2. August 14th, 2009 at 17:59 | #2
Comments are closed.