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.