Do you ever have nightmares where you are back in the Actionscript 2 days and trying to save BitmapData to a JPEG? … ok, so maybe its just me, but who cares because it’s easy now!
Old news…
ByteArray rocks! If you aren’t familiar, it was introduced in AS3 for playing with binary data and has endless uses. Compression being the most obvious, but speed, custom protocols, and streaming data are no less important. zlib and deflate support are built in as well.
Capturing BitmapData, encoding it as a JPG, and saving it through Rails…
Step 1. We need to download the as3corelib. The library we will be using from this package is com.adobe.images.JPGEncoder (a port of this C algorithm), but look around! There are some awesome libraries in here.
Some imports…
import flash.display.MovieClip;
import flash.display.Stage;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.utils.ByteArray;
import com.adobe.images.JPGEncoder;
import flash.events.*;
import flash.net.*;
Capture BitmapData, encode as a JPG, convert to ByteArray, send to Rails
// Capture the BitmapData of the stage for example
var stage_snapshot:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
stage_snapshot.draw(stage);
// Setup the JPGEncoder, run the algorithm on the BitmapData, and retrieve the ByteArray
var encoded_jpg:JPGEncoder = new JPGEncoder(100);
var jpg_binary:ByteArray = encoded_jpg.encode(stage_snapshot);
var header:URLRequestHeader = new URLRequestHeader ("Content-type", "application/octet-stream");
var request:URLRequest = new URLRequest("/generate_jpg");
request.requestHeaders.push(header);
request.method = URLRequestMethod.POST;
request.data = jpg_binary;
var loader:URLLoader = new URLLoader();
loader.load(request);
Rails n’ RMagick…
// Example RMagick usage...
image = Magick::Image.from_blob(request.body.read).first
image.write("#{RAILS_ROOT}/public/jpgs_from_as/test.jpg")
Why it rocks…
Well, just think about what you would have to do without it?
Data transfer – 800×600 sized image…480000 pixels…*~4 (RGBA)…~2Megs? For a ~80kb compressed jpg? No dice.
Data processing – calculating this per pixel color array makes your machine sound like a lawnmower…
I suppose I’ll miss dealing with color palettes and encoding pixel data…NOT!
RightSprite iPhone Dev
14 Comments
GREAT TUTORIAL!! i wanted to say thank you for that. i have another problem. how can i specify where to store the encoded JPG without using rails
What language were you thinking of using to output the JPG?
You could make the request to a PHP script with somethink like the following…
$jpg = $GLOBALS["HTTP_RAW_POST_DATA"];
header('Content-Type: image/jpeg');
header("Content-Disposition: attachment; filename=".$_GET['filename']);
echo $jpg;
Where $_GET['filename'] comes from the get paramters of the request.
Does that help?
The PHP code that Cary Dunn provides above works fine, with some modification for saving it to a file.
< ?
/*
*** THIS CODE IS UNSAFE FOR PRODUCTION ***
This code does absolutely no error checking on the validity of the
expected jpg file coming through. It should be checking that the data
coming in is in fact a valid JPEG file of appropriate dimensions.
*/
$jpg = $GLOBALS["HTTP_RAW_POST_DATA"];
$filename = 'uploads/'.date('r').'.jpg';
file_put_contents($filename, $jpg);
echo "saved to ".$filename;
?>
SORRY, I’M A BIT OF A NEWBIE WHEN IT COMES TO THIS STUFF. YOU WOULD NEED TO CHANGE THE URLREQUEST IN THE FLASH FILE TO RUN THIS PHP SCRIPT, WOULDN’T YOU? AND, IS USING A “LOADER” THE BEST METHOD? OR, WOULD YOU JUST USE “SENDTOURL?”
This code is great!! I am experiencing a problem though. I am using it to capture a video object which is bound to a RTMP stream via netstream/netconnection. Every time I run the above code to capture an image it saves a file with the correct dimensions of the video object (240×180), but image itself is only 160×120 on top of a white canvas. Does this ring any bells?? Any idea whats going on??
Hi I would like to try and just write straight to file from running my flash in an app. I wont be running my classes in a swf in a browser, instead it will be just running on one machine in an art installation. I would like to do something similar to this, but I just need to write straight to a file in a folder, without any sort of prompt or server side scripting. Is this possible?
@Sarah : Reading and writing to local files was added in FP10, so if you are comfortable using 10 (>60% of machines at beginning of 2009) you can checkout the FileReference API.
http://www.mikechambers.com/blog/2008/08/20/reading-and-writing-local-files-in-flash-player-10/ is a good article starter article as well on the topic.
If you need any more help let me know and I can put together an example post.
Thanks man, Great Stuff, this is how i get it worked
image = Magick::Image.from_blob(request.body.read)
image[0].write(“#{RAILS_ROOT}/public/test.jpg”)
you don’t need RMagick for this to work:
File.open(“cockpit_test.jpg”, “wb”) { |f| f.write(request.body.read) }
will work fine
hi
i am new to as3. thanku for the post. can u show an example in which i can send a bitmap as email.thanku once again
Pushpa
Thanks Cary dunn.
Hi, thabks a lot. i have one question, instead of PHP is posible get the image in javascript? is it possible?
by the way, thanks again.
Hi there.
I’m exporting a JPG using AS3/PHP, but my server version is 4.x and it doesn’t work with the function “file_put_contents”
Somebody can’t any idea how to resolve it? (I can’t change of server provider by the momment)
Many thanks!
( Somebody HAVE any idea…)