Flex/Flash/Actionscript

ImageSnapshot class in Flex 3 SDK

There are a few new graphics classes in the Flex 3 SDK that make it easier to create image snapshots of Flex UI components. The ImageSnapshot class provides some static methods for creating snapshots of components and encoding them as PNG or JPEG images. In addition to the ImageSnapshot class, we also get the PNGEncoder, JPEGEncoder, Base64Encoder, and Base64Decoder, which were all previously in the as3corelib project.

mx.graphics.codec.JPEGEncoder
mx.graphics.codec.PNGEncoder

The JPEGEncoder and PNGEncoder classes were in the as3corelib project prior to Flex 3. They have since been rolled into the main Flex framework. Nice! They’re pretty straightforward, and they’ve been around for awhile in the as3corelib project, so they shouldn’t need much explanation.

mx.graphics.codec.IImageEncoder

The IImageEncoder interface defines an interface for a class that encodes a BitmapData object or the raw bytes of a Bitmap into a new encoded ByteArray. The two classes that implement this interface are PNGEncoder and JPEGEncoder. If you were to write your own image encoders you could implement this interface and then you could pass your custom encoder to ImageSnapshot.captureImage() (read below for more on that).

mx.graphics.ImageSnapshot

The ImageSnapshot class is a new addition to the Flex SDK that simplifies the process of capturing an image from a Flex UI control. This is a task that is often performed, I can think of a bunch of examples right off the top of my head where I’ve had to do this. A live reflection class is one candidate to use this new helper class. I have a feeling a big use of this class is going to be saving image snapshots to the user’s computer in an AIR application. And another use-case that I recently dealt with is converting a Flex UI component to a Base 64 encoded image (see my previous post).

When I needed to get a Base64-encoded string of a given Flex UI component I did something like this:


private function getBase64String(component:UIComponent):String) {
	var bitmapData:BitmapData = new BitmapData(component.width, component.height, true, 0xffffff);
	bitmapData.draw(component);

	var bytes:ByteArray = PNGEncoder.encode(bitmapData);

	var b64encoder:Base64Encoder = new Base64Encoder();
	b64encoder.encodeBytes(bytes);

	var b64String:String = b64encoder.flush();
	
	return b64String;
}

But now we have a much easier way. The ImageSnapshot class has a few static methods that we can use. We get:

captureBitmapData
This is the utility function that returns a BitmapData object. This basically saves us a line of code and simplifies the call. Dimensions are capped at 2880 pixels for each side.

captureImage
This returns an ImageSnapshot object. That doesn’t get us all that much, but there are a few pretty cool things. We can pass captureImage a parameter that tells it how to encode the image. PNGEncoder and JPEGEncoder have been rolled into the framework now, so we can pass in either of those and it will encode the image as a PNG or a JPEG.

Once we get the ImageSnapshot object that the static method returns then we can access the byte data of the encoded image with the data property. Then we could pass the JPEG or PNG encoded image to a server to save the file, or if you’re writing an AIR application you could save the file to the hard drive (or drop it onto the clipboard).

encodeImageAsBase64
This function takes an ImageSnapshot object and encodes it as a Base 64 string. Easy enough.

So to go back to the sample code above, now we can generate a Base 64 encoded string like this:


private function getBase64String(component:UIComponent):String) {
	var snapshot:ImageSnapshot = ImageSnapshot.captureImage(component);
	var b64String:String = ImageSnapshot.encodeImageAsBase64(snapshot);

	return b64String;
}

and if you’re too good for three lines of code:


private function getBase64String(component:UIComponent):String) {
	return ImageSnapshot.encodeImageAsBase64(ImageSnapshot.captureImage(component));
}

Bypassing the 2,880 pixel limit
Flash Player has a limitation of only allowing a single bitmap object to have a max width or height of 2,880 pixels. I’ve never run into this problem, but I guess people with massive monitors can have a problem. The ImageSnapshot class does some fancy footwork in the captureImage method that allows you to generate an encoded JPEG or PNG snapshot that is larger than 2,880 pixels. Basically it creates multiple BitmapData objects and stitches them together to form one final ByteArray. Look at the source code for ImageSnapshot and check out the captureAll method.

This gets around the 2,880 pixel limit, but there’s a 256 meg size limit on a single ByteArray object. From the documentation in the ImageSnapshot class: “This ByteArray is limited to around 256MB so scaled images with an area equivalent to about 8192×8192 will result in out of memory errors.”

So nothing groundbreaking here, but we get to save some boilerplate code that we used to have to write to generate a BitmapData object from a Flex UI object, or to generate the bytes of an encoded JPEG or PNG image. I’m guessing a big reason for Adobe including this in Flex 3 is to make it easier to save JPEG or PNG snapshots of charts in an AIR application.

Standard

20 thoughts on “ImageSnapshot class in Flex 3 SDK

  1. Pingback: ImageSnapshot class in Flex 3 SDK « Flash Enabled - Get Ready With Flash…

  2. Pingback: blog.2grafic.com » Blog Archive » Captura de imagenes con Flex3 SDK

  3. wuaiping says:

    if I use captureAll function to capture the image that it’s size is more than 2M ,then the process speed is very very slow.How can I do?

  4. wuaiping says:

    If I use captureAll function to capture the image that it’s size is more than 2M,then the processing speed is very very slowly. How can I do?

  5. Doug

    I see the benefit of the ImageSnapshot for saving an image to file, or sending it over the wire.

    Is there any way to take this image and actually place it on a screen? Ideally as an Image instance. I can’t find any way to trivially convert an ImageSnapshot into an Image instance.

  6. @Bernard,

    try:

    var bitmap:BitmapData = ImageSnapshot.captureBitmapData( …. );

    var img:Image = new Image();
    img.width = bitmap.width;
    img.height = bitmap.height;
    img.source = new BitmapAsset(bitmap);

  7. K Wright says:

    Is it possible to use this method to capture a still image of a live RTMP stream? I’ve tried with the BitmapData.draw(), but I get a 2123 Error (Security Error).

    I thought this might be a better way to do it, but

    imageString = ImageSnapshot.encodeImageAsBase64(ImageSnapshot.captureImage(vidHolder, 0, jpegEnc, true));

    (where vidHolder is a UIComponent holding a video object that is playing the stream) throws the same error (2123).

    Am I using this wrong, or is it not possible…?

  8. Deepak says:

    hi all,

    If i snapshot the datagrid in the UI i am not able to get the complete datagrid values bec of this technique.. Can any one plz help me over here.

  9. Hi Doug, thanks for the lesson on ImageSnapshot. I’m using this to encode flex components, passing the resulting String in XML to a PDF remote object that generates a PDF using LiveCycle’s flex.acrobat classes…pretty nifty!

  10. Lycan says:

    Hi to all,

    I’m having a problem to encode an image. My image have 2 type an medium size image and original size image. I dont have any idea how to encode the original size while I’m am using the medium size for viewing and editing an image.

    Please help me..

    Thank you very much..

  11. Thanks for the article Doug. I was able to use it to save a PNG file on my local computer via a PHP script. I sent the Base64 string using URLRequest:

    var urlRequest:URLRequest = new URLRequest(“server/image.php”);
    urlRequest.method = URLRequestMethod.POST;
    var vars:URLVariables = new URLVariables();
    vars.image = b64String;
    urlRequest.data = vars;
    navigateToURL( urlRequest, “_blank” );

    Image.php:

  12. Sorry – the comment system stripped the PHP code:

    header(‘Content-Type: image/png’);
    header(“Content-Disposition: attachment; filename=title.png”);
    echo base64_decode($_POST[“image”]);

  13. Rob says:

    Excellent article!

    I am having the same trouble Deepak does. I am trying to get a shot of a data grid, but I only get the visible portions. I need an image of the whole grid, even the off screen portions. I’ve tried removing it from the layout, and position it inside an non-visible gigantic container (say 10,000 pixesl square) hoping that it would be laid out fully inside there, and I could then take a snap. However it just becomes oddly sized. Any thoughts?

  14. Mark says:

    Hi, I am trying to connect java script and flex using ExternalInterface. In flex i need to display the image and the url of image is passed from java script.

    java script code..

    flashObject.createMarker(“http://icons.mysitemyway.com/wp-content/gallery/green-grunge-clipart-icons-animals/thumbs/thumbs_012947-green-grunge-clipart-icon-animals-animal-cat-print.png”,25,25);

    and in flex i need to rcv this url and width and height and need to display it please help me out.

    second is that possible to embed a image and convert to class in action script please do replay me back thank you.

  15. Rakesh Amety says:

    Hi,

    I want to generate the crops as same as the original image DPI

    Thanks in advance

  16. nabil says:

    hello;
    i first want to thank you for this great post.
    i’m trying to send the base64_encode through an httpService with the POSTmethod, to a php script and then save the jpg file. to do so, i’m using this php code:

    the result i get is a blank jpg image with the same size as the uicomponent (canvas).
    do you have any idea what is wrong with the code.
    i hope it’s all clear for you. thank you again

  17. nabil says:

    here is the php code :
    if( isset($_POST[‘img’]) ){
    $image = base64_decode($_POST[‘img’]);
    $file = ‘image.jpg’;
    file_put_contents($file, $image);
    }

Comments are closed.