Transform BitmapData into JPEGs (AS3, JPGEncoder, Rails, Rmagick)

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!

14 Comments

  1. maximillion
    Posted November 4, 2008 at 7:11 pm | Permalink

    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

  2. Cary Dunn
    Posted November 4, 2008 at 10:35 pm | Permalink

    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?

  3. Brett Taylor
    Posted November 25, 2008 at 2:14 am | Permalink

    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;
    ?>

  4. GarretT
    Posted November 25, 2008 at 4:42 pm | Permalink

    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?”

  5. Aaron
    Posted February 24, 2009 at 5:32 pm | Permalink

    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??

  6. Posted March 15, 2009 at 9:14 pm | Permalink

    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?

  7. Posted March 15, 2009 at 9:32 pm | Permalink

    @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.

  8. Yau
    Posted March 30, 2009 at 3:14 pm | Permalink

    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”)

  9. thomas
    Posted April 14, 2009 at 12:55 am | Permalink

    you don’t need RMagick for this to work:

    File.open(“cockpit_test.jpg”, “wb”) { |f| f.write(request.body.read) }

    will work fine

  10. pushpa
    Posted June 11, 2009 at 3:28 pm | Permalink

    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

  11. Samar
    Posted July 6, 2009 at 9:12 am | Permalink

    Thanks Cary dunn.

  12. Ato12
    Posted August 3, 2009 at 5:50 pm | Permalink

    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.

  13. MickyMike
    Posted August 10, 2009 at 4:20 pm | Permalink

    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!

  14. Micky Mike
    Posted August 10, 2009 at 4:42 pm | Permalink

    ( Somebody HAVE any idea…)
    :)

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">