# Create a Snappy Snapshot App with Flash Builder 4

##### Tutorial Details
• Difficulty: Intermediate
• Program: Flash Builder 4
• Estimated Completion Time: 45 mins

There are many sites where you can choose your profile image by taking a picture with your webcam, instead of uploading one. This tutorial will teach you how to take a picture and do whatever you want with it, using Flash Builder 4 with Ruby on Rails or PHP.

## Final Result Preview

Click on the demo link above, but bear in mind that you won’t be able to use the ‘Save’ function unless you run it yourself on a server which supports PHP. You can “Right click > View source” to see the application source.

## Step 1: Flash Builder 4 Considerations

In order to take full advantage of this tutorial, it’s recommended that you already know some of the new features of Flash Builder 4, like the new namespaces and components. Also, you’ll need Flash Builder 4 to run the source code without having to change anything.

Flex 3 users: don’t worry, you can still follow this tutorial. You’ll need to change all the “fx” and “s” namespaces to “mx”, example: “<s:Button>” becomes “<mx:Button>”. The “Declaration” tag does not exist (write what’s inside it, outside). “Group” and “BorderContainer” will be “Canvas”. “VGroup” will be “VBox”. “HGroup” will be “HBox”. And there is no “chromeColor” (you will need to style the button differently).

## Step 2: Create a New Flex Project

First of all, we need to create a new Flex Project. Open Flash Builder 4 and click “File > New > Flex Project”.

The following dialog will open:

Choose a “Project Name”: in our case it will be “CameraSnapshot” but you can use whatever you want. You can also set the "Project location" to anywhere you want. As it will run in the browser, we will leave “Web” checked. We will use the default SDK version and we won’t choose any server technology.

Hit Next.

We won’t change anything here, hit Next.

In this following step we will also use the default settings, so click Finish:

Our project has been created. This is a fresh new Flash Builder 4 app!

## Step 3: Create an ActionScript File

We will have an external ActionScript file that will perform all the logic for us.

Create a new ActionScript file: File > New > ActionScript File

Give it a name, we’ll choose: "cam" but again, it can be whatever you want:

You can leave the “Package” blank. Hit Finish. Now let’s start coding!

## Step 4: Camera Placeholder

Now that our project has been created, we’ll need a place to display our camera. Lets add a VideoDisplay to our CameraSnapshot.mxml file, after the "Declarations" tag:

<mx:VideoDisplay id="theCam" width="533" height="400"/>


The id is important because that’s how we refer to this specific VideoDisplay.

You may change the width and height of the VideoDisplay to anything you want, but remember to keep a 4:3 aspect ratio to avoid image distortion. Unless you are dealing with a specific case.

Also, notice that we’ve used the “mx” namespace prefix instead of “s”. If we use the “s” namespace prefix here, Flash Builder will throw an error when we try to use the method “attachCamera”. We will see this method in the next step.

## Step 5: Getting the Camera

Now that we have place to display the user’s camera, let’s get it! Create a new function inside the file cam.as:

private function getCam():void
{
if (Camera.getCamera())
{
// assign the user's default camera to a variable
var camera:Camera = Camera.getCamera();

// set the camera quality to be the highest as possible
camera.setQuality(0, 100);

// set the width, height, frames per second
camera.setMode(theCam.width, theCam.height, 30);

// attach the camera to our "theCam" VideoDisplay
theCam.attachCamera(camera);
}

else
{
}

}


Notice that we have a conditional: we will only move on if we can get at least one camera from the user. Next, we called it “camera” for convenient purposes and configured it in the next few lines.

In camera.setMode, you should understand “theCam.width” as “the width of our VideoDisplay”. In Flex, this is called Data Binding. In plain english: “the width and height of the ‘camera’ will always and automatically be the same width and height of the ‘theCam’”. So, if you decide to change the size of the VideoDisplay later, the camera’s size will change automatically.

After getting and configuring our camera, we attach it to our “theCam”. It tells our VideoDisplay what to display.

## Step 6: Displaying the Camera

Lets import our cam.as to our CameraSnapshot.mxml file, otherwise we won’t have access to the function we just made:

<fx:Script source="cam.as"/>


If you saved your “cam.as” in a different folder, just add the folder name before “cam.as”, for instance: “different_folder/cam.as”

Now we need to tell our application to actually run this function. We’ll add a “creationComplete” method calling “getCam();” inside the opening “Application” tag. It means that our camera will be displayed as soon as the application is completely created:


creationComplete="getCam();">


## Step 7: First Run

So far, so good. Now, run the application and see yourself inside it before we move to the next step :)

Notice: a few users, specially on a Mac, may have to change the default camera that Flash Player is getting. Inside the running app: Right click (or cmd + click) > Configurations … > Click the “webcam icon” tab below > Change it to your “real” cam.

## Step 8: Layout and Positioning

In this step we’ll wrap our “VideoDisplay” tag with a “VGroup” to layout the elements that we’ll add, vertically. You’ll see it yourself later.

<s:VGroup horizontalCenter="0" verticalCenter="0">
<mx:VideoDisplay id="theCam" width="533" height="400"/>
</s:VGroup>


Notice the “horizontalCenter” and “verticalCenter” properties set to “0″. This means that the “VGroup” will be 0 pixels away from the center of the parent container, in our case, the whole application.

You can run the application again: resize your browser’s window and notice that you are always in the middle.

## Step 9: Capture Button

In order to add our “Take a picture” button, we’ll need to wrap our “VideoDisplay” with a “Group” tag where the layout is absolute and everything is placed on top of each other (unless you position them with X and Y or place them some pixels away from the top, right, bottom or left).

Your code should look like this:


<s:VGroup horizontalCenter="0" verticalCenter="0">
<s:Group id="videoArea">
<mx:VideoDisplay id="theCam" width="533" height="400"/>
</s:Group>
</s:VGroup>


Notice that we’ve just added the “Group” tag. It’s inside our recently added “VGroup” and wraps our well known “VideoDisplay”

Now we add the “Take a picture” button. It will appear inside a nice semi-transparent “BorderContainer” that we’ll write below our “VideoDisplay”, take a look:


<mx:VideoDisplay id="theCam" width="533" height="400"/>

<s:BorderContainer
bottom="0"
width="100%"
backgroundColor="black"
backgroundAlpha="0.4"
borderColor="black"
height="55">

<s:Button
id="trigger"
horizontalCenter="0"
verticalCenter="0"
label="Take a picture!"
height="35"/>

</s:BorderContainer>


Notice that our button area is “0″ pixels away from the bottom and it has a black semi-transparent (backgroundAlpha) background. We also added our capture button called “trigger”. It is placed right in the middle of our “BorderContainer”.

## Step 10: Button Style

Add “chromeColor” and “color” to our “trigger” button and our code should look like this:


<s:Button
id="trigger"
horizontalCenter="0"
verticalCenter="0"
height="35"
label="Take a picture!"
chromeColor="#33abe9"
color="#ffffff"/>


You can run the app again and see how we’re doing.

## Step 11: Picture Preview Placeholder

Now we’ll add a placeholder where we can preview the picture that we’ll take later. Write it below our “VideoDisplay” and above our “BorderContainer”.


<s:Group id="previewBox" visible="false">
<mx:Image id="preview" width="100%" height="100%"/>
</s:Group>


We’ve added a “Group” called “previewBox” that wraps an “Image” called “preview”.

## Step 12: Preparing for the Snapshot

Add the following code at the top of our “cam.as” file.


// ActionScript file

import flash.display.BitmapData;

import mx.graphics.codec.JPEGEncoder;
import mx.rpc.http.HTTPService;
import mx.utils.Base64Encoder;

private var bm:BitmapData;


Here we’ve just imported everything that we’ll need in order to take and send the picture to the server.

## Step 13: Take a Picture!

Now it’s time to take a picture. Let’s add a function that will do it:



public function takePicture():void {

//if we are not previewing any picture, we'll take one :)
if (!previewBox.visible) {

//create a BitmapData variable called picture that has theCam's size
var picture:BitmapData = new BitmapData(theCam.width, theCam.height);

//the BitmapData draws our theCam
picture.draw(theCam);

//Our preview's source is a new Bitmap made of picture's BitmapData
preview.source = new Bitmap(picture);

//stores this BitmapData into another BitmapData (outside this function)
bm = picture;

//makes the previewBox visible, so we can see our picture
previewBox.visible = true;

//change our trigger label, so the user will be able to try again
trigger.label = "Take another picture...";

//changes the color of the button
trigger.setStyle('chromeColor', '#ff0000');

}

//if we are previewing a picture...
else {

//makes the previewBox invisible
previewBox.visible = false;

//changes the label
trigger.label = 'Take a picture!';

//changes the color of the button
trigger.setStyle('chromeColor', '#33abe9');

}

}



The comments above “// (…)” will tell you what’s going on.

Now, add a “click” property inside our “trigger” button (CameraSnapshot.mxml) to call our recently created “takePicture” function:


<s:Button
id="trigger"
horizontalCenter="0"
verticalCenter="0"
height="35"
label="Take a picture!"
chromeColor="#33abe9"
color="#ffffff"
click="takePicture();"/>


Run the app and Take a picture!

## Step 14: Adding Cool Effects

Now we add some cool effects: when we take a picture, we’ll see a flash light. When we discard a picture, it will go away. Change the “Declarations” tag, by adding the following code:


<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->

<s:children>
<mx:Zoom
duration="350"
zoomWidthFrom="1.0"
zoomWidthTo="0.01"
zoomHeightFrom="1.0"
zoomHeightTo="0.01"
target="{previewBox}"/>
</s:children>
</s:Parallel>

</fx:Declarations>


The “Fade” tag will make the flash light disappear realistically. The “Parallel” tag will run the “Zoom” and “Fade” at the same time, discarding our photo with style.

## Step 15: The Flash Effect

Let’s add our flash light below the “preview” Image:


<mx:Image id="preview" width="100%" height="100%"/>

<s:BorderContainer
id="flashLight"
width="100%"
height="100%"
hideEffect="{flashFX}"
backgroundColor="white"
backgroundAlpha="0.8"/>


Notice the “hideEffect” set to “{flashFX}”: when the “flashLight” becomes invisible, this effect will be triggered. Also, the “backgroundAlpha” is set to “0.8″ so our flash light is not that bright. Our flash light is just a white BorderContainer that shows up and then quickly goes away, creating the “flash” effect.

Now we just need to set the “flashLight” visible property to “true” and “false” (activating the flash effect) inside our “takePicture” function that will now look like this:


public function takePicture():void {

//if we are not previewing any picture, we'll take one :)
if (!previewBox.visible) {

//create a BitmapData variable called picture that has theCam's size
var picture:BitmapData = new BitmapData(theCam.width, theCam.height);

//the BitmapData draws our theCam
picture.draw(theCam);

//Our preview's source is a new Bitmap made of picture's BitmapData
preview.source = new Bitmap(picture);

//stores this BitmapData into another BitmapData (outside this function)
bm = picture;

//makes the previewBox visible, so we can see our picture
previewBox.visible = true;

//displays the flashLight
flashLight.visible = true;

//makes the flashLight go way
flashLight.visible = false;

//change our trigger label, so the user will be able to try again
trigger.label = "Take another picture...";

//changes the color of the button
trigger.setStyle('chromeColor', '#ff0000');

}

//if we are previewing a picture...
else {

//makes the previewBox invisible
previewBox.visible = false;

//changes the label
trigger.label = 'Take a picture!';

//changes the color of the button
trigger.setStyle('chromeColor', '#33abe9');

}

}


## Step 16: Discard Picture Effect

Change the "Group" called “previewBox” (CameraSnapshot.mxml) so it uses the “discardPhoto” effect:




Notice the “hideEffect” again. Run the app, take a picture, take another and see the effects!

## Step 17: Save Button

Lets add a Save and Cancel button right below the closing tag of our “Group” called “videoArea” and above the “VGroup” closing tag:


<s:HGroup verticalAlign="middle" horizontalAlign="right" width="100%">
<s:Button
id="savePic"
label="Save picture"
height="30"
enabled="false"
</s:HGroup>


We wrapped the “Cancel” and “Save a picture” buttons inside an “HGroup” tag (which will display them horizontally). We’ve set the “verticalAlign” property to “middle” so the “Cancel” button is placed in the middle of the “savePic” height. We also set the “width” to “100%” and “horizontalAlign” to “right”.

Notice that the “Save picture” button is disabled. We will enable it when the user is previewing a picture and disable when not. You can make the Cancel button go to the previous page, close the pop-in that wraps the SWF, etc… It’s your call.

Inside the “cam.as” file, after some changes, our “takePicture” function will now be looking like this:


public function takePicture():void {

//if we are not previewing any picture, we'll take one :)
if (!previewBox.visible) {

//create a BitmapData variable called picture that has theCam's size
var picture:BitmapData = new BitmapData(theCam.width, theCam.height);

//the BitmapData draws our theCam
picture.draw(theCam);

//Our preview's source is a new Bitmap made of picture's BitmapData
preview.source = new Bitmap(picture);

//stores this BitmapData into another BitmapData (outside this function)
bm = picture;

//makes the previewBox visible, so we can see our picture
previewBox.visible = true;

//displays the flashLight
flashLight.visible = true;

//makes the flashLight go way
flashLight.visible = false;

//change our trigger label, so the user will be able to try again
trigger.label = "Take another picture...";

//enables the savePic button
savePic.enabled = true;

//changes the color of the button
trigger.setStyle('chromeColor', '#ff0000');

}

//if we are previewing a picture...
else {

//makes the previewBox invisible
previewBox.visible = false;

//changes the label
trigger.label = 'Take a picture!';

//disables the savePic button
savePic.enabled = false;

//changes the color of the button
trigger.setStyle('chromeColor', '#33abe9');

}

}


Above, we’ve just added 2 lines of code to enable and disable the Save button.

## Step 18: Saving the Picture

Now we’ll look at one of the many things that you can do with your picture: sending it to the server. In doing so, you can assign it as a user’s profile picture, a new album photo, etc…

Let’s create a function that sends our picture to the server when we click “Save a picture”:


public function savePicture():void {

//change the savePic button label so the user knows as soon as possible
//that we are saving his picture
savePic.label = "Saving..."

//disables the button so the user don't click it twice
savePic.enabled = false;

//the trigger button displays a nice message
trigger.label = "That's a nice picture :)"

//disables the "trigger" button, now is too late to take another picture!
trigger.enabled = false;

//creates a new JPEGEncoder called "je"
//sets the quality to 100 (maximum)
var je:JPEGEncoder = new JPEGEncoder(100);

//creates a new ByteArray called "ba"
//JPEGEnconder encodes our "bm" Bitmap data: our "picture"
var ba:ByteArray = je.encode(bm);
//this ByteArray is now an encoded JPEG

//creates a new Base64Encoder called "be"
var be:Base64Encoder = new Base64Encoder();

//encodes our "ba" ByteArray (wich is our JPEG encoded picture) with base64Encoder
be.encodeBytes(ba);

//Now we have our "encodedData" string to send to the server
var encodedData:String = be.flush();

//this is the HTTPService that we will use to send our data to the server
var handleService:HTTPService = new HTTPService();

//now we set what URL we want... Set the URL of your server-side page/action
//this is a typical Ruby on Rails URL. Controller: users_controller, Action: handlepicture
handleService.url = "http://localhost:3000/users/camerasnap";

//another example of URL:
//appUrl.url = "http://www.example.com/handlePicture.php";

//or, a relative path:
//appUrl.url = "/handlePicture.php"

//we choose POST as our method
handleService.method = "POST";

//here we show the busy cursor for better visual feedback
handleService.showBusyCursor = true;

//Finally, we send our "encodedData" as a "content" variable
handleService.send({content: encodedData});

// 1 - in your server-side code you can handle the "param" or "post" variable called "content"
// 2 - use a base64 decoder
// 3 - write it to disc (now you have a real image saved in your server)
// 4 - make this image the user's profile picture or anything you want

}


In this function we do three things: change some labels and disable some buttons, encode our picture to JPEG and, finally, send the encoded data (Base64 string) to the server.

Again, the comments above “// (…)” can tell you how we did that.

Now our “Save picture” button needs to trigger the “savePicture” function. Add a "click" method:


<s:Button
id="savePic"
label="Save picture"
height="30"
enabled="false"
click="savePicture();"
/>


## Step 19: Server-side Handling

In the following steps, I wrote only the necessary code so you can do anything you want with the saved picture file. You’ll have to write the code to make “example_name.jpg” the user’s profile picture (for example). Unfortunately, I cannot cover how you can accomplish that as it changes a lot depending on your current solution. Room for another tutorial I guess..

The following example shows how to save the picture into your server using Ruby on Rails or PHP, it’s pretty simple!

## Step 20: Server-side Handling Ruby on Rails

  require "base64"

def camerasnap

#associate the param sent by Flex (content) to a variable
file_data = params[:content]

#Decodes our Base64 string sent from Flex
img_data = Base64.decode64(file_data)

#Set an image filename, with .jpg extension
img_filename = "example_name.jpg"

#Opens the "example_name.jpg" and populates it with "img_data" (our decoded Base64 send from Flex)
img_file = File.open(img_filename, "wb") { |f| f.write(img_data) }

#now we have a real JPEG image in our server, do anything you want with it!
#Write what's necessary to make it a profile picture, an album photo, etc...

end


## Step 21: Server-side Handling PHP



<?php

//associate the param sent by Flex (content) to a variable
$file_data =$_POST['content'];

//Decodes our Base64 string sent from Flex
$img_data = base64_decode($file_data);

//Set an image filename, with .jpg extension
$img_filename = "example_name.jpg"; //Opens the "example_name.jpg"$fp = fopen ($img_filename, "w"); //populates it with "img_data" (our decoded Base64 send from Flex) fwrite ($fp, $img_data); //closing the file pointer fclose ($fp);

//now we have a real JPEG image in our server, do anything you want with it!
//Write what's necessary to make it a profile picture, an album photo, etc...

?>



These two examples above (Rails and PHP) are as simple and clear as possible. You can write them in just 1 line of code (Rails) and 2 lines (PHP) if you want.

## Step 22: Exporting Release Build

Before uploading the SWF to your site, it’s recommended that you export it as an optimized SWF (release build):

After exporting, you will have to upload everything that’s inside the “bin-release” folder (located inside your project folder).

## Conclusion

I hope you’ve liked this tutorial! There are many things that you can do with this “real-time picture”, I’m already using it in production so my users can quickly change their profile picture. Tell us what you think would be a creative or innovative use of this feature in the comments below. Thanks!

• TuTbaker

Chrome 6 (Flash plugin crush down), Firefox 3.6(crash down)….
Very nice! :)

• http://ste Steve

Doesn’t work with Mac Safari Version 4.0.5, nothing shows up it’s just black the whole time. Same as FF 3.6.3

• Alex M

@Steve

Did you read this? Notice: a few users, specially on a Mac, may have to change the default camera that Flash Player is getting. Inside the running app: Right click (or cmd + click) > Configurations … > Click the “webcam icon” tab below > Change it to your “real” cam.

@Gustavo

Great tute! It’s my first look at Flex and I am really impressed. I have a small project coming up that I was going to do in Flash, but after this, I think I might look at going down the Flex road. So much simpler to develop a clean interface.

I am having one issue with this tute, with it not saving the image on my server (using the PHP script). I keep getting a 0 bytes jpg file. I might have made a typo somewhere…

• http://www.pligus.com Gustavo Scanferla

@Alex M

I’m happy that you liked it, go down the Flex road!

I’ve just tried the PHP again, with tut’s “copy-pasted” code and it’s working fine.
I don’t know what may be in your case. Will keep trying here.

• Coen86

Do i need to make a php file for saving it in order 2 communicate with the html file?

• Pashka

works for me
firefox 3.6.3 works
opera 10.53 works
thanks

• http://josecamposcr.blogspot.com/ Jose Campos

Really nice tutorial, i love that it is developed with Flash Builder, thanks for sharing your knowledge. I would add color effects(i know how) and if you have any idea of how to apply visual effects(mac camera type) and you want to share that with us that would be really amazing!!!

• Jeff

I’ve gone over this several times, but don’t see where you’re connecting your app to the php or ruby files. Am I blind?

• http://www.pligus.com Gustavo Scanferla

@Jeff

You’re not blind ;)

Step 18, right below the following text:
“Let’s create a function that sends our picture to the server when we click “Save a picture”:”

Click: “show source”
I don’t know why it’s collapsed, but it is :P

• http://michaeljameswilliams.com/ Michael Williams

Aha, we were experimenting with the new “collapse” feature of the codebox, making sure it works. Guess we learned something about its user-friendliness, too ;)

I’ve un-collapsed it now to make it clearer.

• http://www.patrickscottmusic.com Patrick

Gustavo,

First, thank you for the tutorial. It’s brilliant.

My question, is there a way to do the same thing but just with audio? I have a music website that I would like people to post audio comments on. I know there is a way just not sure how.

Thanks in advance for any insight you might have.

• http://beasrilankan.com/ Sameera Thilakasiri

I’m wondering, can we save files using Flex, without AIR?

• Ben Taitelbaum

In case anyone else runs into the demo not working with their built-in iSight camera, I followed the advice from http://discussions.info.apple.com/thread.jspa?messageID=12694240 (uninstall google’s voice and video plugins) and now it works.

• http://nerdcantina.blogspot.com punk

hello great tutorial…
im stuck in step 15

Description Resource Path Location Type
Se debe terminar el tipo de elemento ‘s:Group’ mediante la coincidencia con la etiqueta de cierre ”. camerasnapshot.mxml /camerasnapshot/src line 39 Flex Problem

is my first time using this kind of technology i hope you can help me :)

• hello

Hello i want to have Step 21: Server-side Handling PHP
to post to my localhost
but i don’t understand that step

i decided using php
so i edited like this can you correct me?

public function savePicture():void {

//change the savePic button label so the user knows as soon as possible
//that we are saving his picture
savePic.label = “Saving…”

//disables the button so the user don’t click it twice
savePic.enabled = false;

//the trigger button displays a nice message
trigger.label = “That’s a nice picture :)”

//disables the “trigger” button, now is too late to take another picture!
trigger.enabled = false;

//creates a new JPEGEncoder called “je”
//sets the quality to 100 (maximum)
var je:JPEGEncoder = new JPEGEncoder(100);

//creates a new ByteArray called “ba”
//JPEGEnconder encodes our “bm” Bitmap data: our “picture”
var ba:ByteArray = je.encode(bm);
//this ByteArray is now an encoded JPEG

//creates a new Base64Encoder called “be”
var be:Base64Encoder = new Base64Encoder();

//encodes our “ba” ByteArray (wich is our JPEG encoded picture) with base64Encoder
be.encodeBytes(ba);

//Now we have our “encodedData” string to send to the server
var encodedData:String = be.flush();

//this is the HTTPService that we will use to send our data to the server
var handleService:HTTPService = new HTTPService();

//now we set what URL we want… Set the URL of your server-side page/action
//this is a typical Ruby on Rails URL. Controller: users_controller, Action: handlepicture
//handleService.url = “http://localhost:3000/users/camerasnap”;

//another example of URL:
//appUrl.url = “http://localhost/handlePicture.php”;

//or, a relative path:
//appUrl.url = “/handlePicture.php”

//we choose POST as our method
handleService.method = “POST”;

//here we show the busy cursor for better visual feedback
handleService.showBusyCursor = true;

//Finally, we send our “encodedData” as a “content” variable
handleService.send({content: encodedData});

// 1 – in your server-side code you can handle the “param” or “post” variable called “content”
// 2 – use a base64 decoder
// 3 – write it to disc (now you have a real image saved in your server)
// 4 – make this image the user’s profile picture or anything you want

}

do i have to create a php file using this code?

i created and i put it in localhost/handlepicture.php

but eclipse says
Description Resource Path Location Type
1120: Access of undefined property appUrl. cam.as /CameraSnapshot/src line 138 Flex Problem

because i decided to use php instead of ruby on rails

• http://sixworks.co.uk James

Is it possible to trigger the photo action through javascript in the page containing the flash file?
I’m a flash dunce, so if someone knows how to achieve this, please get in touch here: http://sixworks.co.uk/contact

• BillyTheKid

Thank you very much for this userful and well made tutorial !