Welcome!

Adobe Flex Authors: Yakov Fain, Keith Swenson, Jacques Durand, Pat Romanski, Liz McMillan

Related Topics: Adobe Flex, Java, ColdFusion

Adobe Flex: Article

Binary Data, ColdFusion & Adobe Flex

Sending BitmapData to a server and saving it as a JPG file

Several months ago I posted some articles on my blog about Flex 2 components and accessing/modifying their BitmapData. In one example, I sent the BitmapData to the server and saved it as a JPG file, and I've been asked numerous times since... "How did you do that?" It's surprisingly easy to do once you understand the concepts involved. There are four ways to get binary data from the Flex application back to your server: AMF3 (RemoteObject), Web Services, HTTP Services, or through a Socket connection. In this article I'll cover the first three topics as they pertain to Flex 2; Socket connectivity could take an article all by itself.

Binary data can't be pushed to the server in its native format using a Web Service or a standard HTTP POST method. To save the data using Web Services or HTTP POST, you must first convert the binary data to a text string using Base64-encoding. On the other hand, AMF3 (RemoteObject method) lets you send the binary data to the server in its native binary form. One thing to keep in mind with Base64-encoding is that the encoding process will actually increase the size of the data that's being sent across the wire.

Regardless of how you're sending the data to the server, it's a good practice to compress the data client side whenever possible. I've used the JPGEncoder class at http://code.google.com/p/as3corelib with great success. You can use this class to convert binary image data into a compressed JPG ByteArray that can be sent to the server. This is a good practice for two reasons:

  • The data is compressed, which helps decrease latency when communicating with the server.
  • The data is encoded into the format that you want to save, so no additional processing/conversion is required on the server. You simply need to save the data either in your file system or in a binary object in your database.
Here's how you get data from a Flex component into a JPG ByteArray: First, you'll have to retrieve the BitmapData from your Flex component. You can pass any Flex component into the following function to retrieve its BitmapData:

private function getUIComponentBitmapData( target : UIComponent ) : BitmapData
{
var bd : BitmapData = new BitmapData( target.width, target.height );
var m : Matrix = new Matrix();
bd.draw( target, m );
return bd;
}

Once you have the BitmapData, you'll have to create an instance of the JPGEncoder class and encode the BitmapData. (This example uses the JPG quality of 75.) It's also important to remember that your Flex application will have a slight pause while the encoding is being processed:

var bd : BitmapData = getUIComponentBitmapData( paintCanvas );
var encoder : JPEGEncoder = new JPEGEncoder(75);
var data : ByteArray = encoder.encode( bd );

Once you have the data converted to a JPG ByteArray, you're ready to push it to the server and save it. The fastest and easiest way to do that is to use a RemoteObject method and serialize the data using AMF3. This example shows you a method in a ColdFusion Component (CFC) that will let you send the data and save it to the local file system:

<cfcomponent name="ImageSave" displayname="ImageSave" output="false">
   <cffunction name="ROsave" access="remote" output="false" returntype="void">
     <cfargument name="data" type="binary" required="true" />
     <cffile action="write" file="c:\temp\ro_data.jpg"
output="#arguments.data#" />
   </cffunction>
</cfcomponent>

You can see that the code is actually very simple. The CFC's ROsave (remote object save) method is expecting binary data as a parameter. When executed, the data is written to the file system using the <CFFILE /> "write" method.

On the Flex side, we'll have to instantiate a mx:RemoteObject:

<mx:RemoteObject
id="ro"
showBusyCursor="true"
destination="ColdFusion"
source="BinaryData.cf.ImageSave">

<mx:method name="ROsave"
result="onResult(ÔData Saved via mx:RemoteObject')"
fault="onFault(event)" />
</mx:RemoteObject>

To save the data, we'll invoke the ROsave method and pass the JPG-encoded ByteArray as a parameter:

var bd : BitmapData = getUIComponentBitmapData( paintCanvas );
var encoder : JPEGEncoder = new JPEGEncoder(75);
var data : ByteArray = encoder.encode( bd );
ro.ROsave( data );

If you aren't using remoting, you can save the data using Web Services or HTTP services. Most seasoned ColdFusion developers might stop me here and say... "If you're using CFCs as Web Services, why wouldn't you just use them as RemoteObject methods since they are faster?" My response is this: This is just an example. You may be able to take this method and apply it to other technologies where it may be applicable (.NET, Java, PHP, etc.).

<cfcomponent name="ImageSave" displayname="ImageSave" output="false">
   <cffunction name="WSsave" access="remote" output="false" returntype="void">
     <cfargument name="data" type="string" required="true" />
     <cffile action="write" file="c:\temp\ws_data.jpg"
output="#ToBinary(arguments.data)#" />
   </cffunction>
</cfcomponent>


More Stories By Andrew Trice

Andrew Trice is a consultant with Cynergy Systems in Washington, DC, where he specializes in development of Flex-based Rich Internet Applications. Andrew has over 5 years of proven experience in the RIA industry, including application design and development using Flex, Flash, ColdFusion, J2EE and .NET architectures.

Comments (1) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Wiskers69 10/13/09 03:17:00 PM EDT

Andrew I am hoping you can help me.
I have a .NET web service I need to use to upload a jpeg image. The web service takes 2 arguments, a byte array and a file name.

I now want to call this web service from a flex app. I can call the service but nothing happens, I don't get an error and I don't get my file uploaded. The code I'm using is:

uploadByteArray = new ByteArray;
jpg = new JPEGEncoder(75);
var bitmapData:BitmapData = new BitmapData(uploadimage.width,uploadimage.height);

bitmapData.draw(uploadimage);
var quality:int = 75;
uploadByteArray = jpg.encode(bitmapData );

UploadService.ProcessRequest.send

in the code above I bind the variable uploadByteArray to the first input parameter of the websivice.

Any help or suggestions would be greatly appreciated.