GhostWire Studios - Flash/Flex UI Components Development And Consulting Services
Quality User Interface Controls For Flash Application DevelopmentAspireUI Components

Dec 03 2009

[AS3] Serializing Bitmaps (Storing BitmapData As Raw Binary/ByteArray)

Published by sunny at 2:46 pm under Flash, Flash AS3, Tips

Whenever an application needs to save bitmap images to local storage or post them to a server script, a common practice is to encode the image as JPEG or PNG before sending that binary data off as the respective mimeType. However, if the intention is simply to save the bitmap image, ie to serialize the BitmapData, then converting the image to JPEG/PNG would actually be unnecessary.


BitmapData to ByteArray
To get a byte array representing the BitmapData, all you need to do is to call the getPixels() method. The getPixels() method requires you to specify the rectangular area to capture; the most convenient way to specify this would be to use the rect property of the BitmapData you are serializing.

// ActionScript 3.0
 
// assuming you have a Bitmap object "bitmapImage" that you would like to serialize
var bytes:ByteArray = bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect);

The method returns a ByteArray object, with each pixel in the BitmapData represented by an unsigned integer, ie four (4) bytes, in the ByteArray. This means that you can expect a 20×20 bitmap image to be represented by a ByteArray object that has 1600 bytes (20 x 20 x 4 = 1600) before compression.

After you have the ByteArray object, compress it:

var bytes:ByteArray = bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect);
bytes.compress();

That effectively gives you the lossless compressed binary data of the bitmap image.


Bitmap Dimensions (Width And Height)
So, getting the ByteArray representation of a bitmap image is simple – just call the getPixels() method.

However, in order for the data to be useful, we must be able to re-construct the bitmap image from it. The byte array in itself does not give any clue as to the dimensions of the bitmap image, only the total number of pixels. This means that you must store the dimensions of the bitmap image as well. Actually, you only need to store either the width or the height, because you can compute the other side once you have either one since you also know the total number of pixels.

In the code below, we will store information about the width of the BitmapData in the first four (4) bytes, followed by the byte array representing the image:

var bytes:ByteArray = new ByteArray();
bytes.writeUnsignedInt(bitmapImage.bitmapData.width);
bytes.writeBytes(bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect));
bytes.compress();


Saving To File
Once the above is done, you can save the binary data normally (by posting it to a server script, via AIR local filesystem API, via SharedObject, via FP10 FileReference, etc.).

For this example, we will save the binary data to file using the save() method of the FileReference class (available when targeting Flash Player 10). As a security measure, the save() method will only work in the Flash Player if you call it in response to a user event (for example, MouseEvent.CLICK event). Therefore, you need to create a button, attach a listener to it, and call the save() method in the event handler.

// ** must target Flash Player version 10+ **
function on_buttonClick(evt:MouseEvent):void
{
	var bytes:ByteArray = new ByteArray();
	bytes.writeUnsignedInt(bitmapImage.bitmapData.width); // store width of image
	bytes.writeBytes(bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect)); // store bitmapdata as bytearray
	bytes.compress();
	new FileReference().save(bytes, "image.bmd"); // default name "image.bmd"
}

You can give the file any name, any extension. In the example code above, I gave the saved file a “.bmd” extension (BitmapData), but this is just a fictitious file type. The resulting file has no valid mimeType and does not work as any known file type – it is our own custom binary file format that is useful only for storage and subsequently re-used by our own application code.


ByteArray to BitmapData
As mentioned above, in order for the saved data to be useful, we must be able to re-construct the original bitmap image from it.

First, we load the file normally via URLLoader:

var ldr:URLLoader	= new URLLoader();
ldr.dataFormat	= URLLoaderDataFormat.BINARY; // ** make sure you do this **
ldr.addEventListener(Event.COMPLETE, on_fileLoad);
ldr.addEventListener(IOErrorEvent.IO_ERROR, on_fileLoadError);
ldr.load(new URLRequest(pathToBitmapDataFile));

The following shows a simple on_fileLoad handler:

function on_fileLoad(evt:Event):void
{
	if (evt.type == Event.COMPLETE)
	{
		var data:ByteArray = URLLoader(evt.target).data as ByteArray;
		if (data)
		{
			try
			{
				data.uncompress();
			}
			catch(e:Error)
			{
			}
			// data is now the uncompressed byte array
			// ... process data ...
		}
	}
}

We need to recall the dimensions of the bitmap image. Remember that we saved the value of the width in the first four (4) bytes of the binary data:

// after data.uncompress()
var width:int = data.readUnsignedInt(); // first 4 bytes (unsigned integer)

We can then derive the height:

// after data.uncompress()
var height:int = ((data.length - 4) / 4) / width;
// (data.length - 4) ** byte array less the first four bytes gives the representation of the bitmap **
// ((data.length - 4) / 4) ** length of the representation is divided by four because each pixel takes four bytes **
// ((data.length - 4) / 4) / width ** remember, it is a rectangle, so we can get the height this way **

NOTE: If you want to skip “dimension derivation”, you can store both width and height in your binary data. Either way will work, the choice is yours.

Once you know the dimensions, you can re-construct the Bitmap object using the setPixels() method:

var bmd:BitmapData = new BitmapData(width, height, true, 0); // 32 bit transparent bitmap
bmd.setPixels(bmd.rect, data); // position of data is now at 5th byte
 
var bm:Bitmap = new Bitmap(bmd);
addChild(bm);


Conclusion
The above shows how you can convert BitmapData to a ByteArray, save that ByteArray, and re-construct the BitmapData from the saved ByteArray.

Although the basic purpose would be to save bitmap images to server/local storage, there would also be other scenarios where the above technique will be useful. For example, after you obtain the ByteArray representation of the image, you can post it to your server for further processing. You can also use the technique to trim down your external JPEG/PNG image files, stripping away all meta information from the JPEG/PNG encoding leaving behind only the raw image data (possibly resulting in smaller file sizes). Of course, the resulting binary files will no longer work as JPEG/PNG image files, but your applications will be able to reconstruct the images easily during run-time. Actually, you can also consider this as a way to protect your external image files from unwanted hot linking.

pixelstats trackingpixel
Share or Bookmark This Post:
  • StumbleUpon
  • email
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Live
  • Yahoo! Buzz
  • Netvibes
  • NewsVine
  • Reddit
  • Slashdot
  • Technorati
  • BlinkList
  • Mixx
  • Diigo
  • Faves
  • Suggest to Techmeme via Twitter
  • Twitter

Other Posts You Might Enjoy:

         

6 responses so far

6 Responses to “[AS3] Serializing Bitmaps (Storing BitmapData As Raw Binary/ByteArray)”

  1. Ian Fordon 04 Dec 2009 at 12:39 am

    Clever! I especially like the idea of using this technique to prevent hotlinking.

  2. Ronny Karamon 04 Dec 2009 at 3:12 pm

    I totally agree with Ian.
    It’s actually really useful to protect ur media files in a way.

  3. jeanphilippeon 05 Dec 2009 at 4:43 pm

    Hi man,
    Thanks for this good way !
    just an little mystake here : readUnsignedInteger() > readUnsignedInt()
    i’ve put a post on my blog, i’ve hope it’s not a problem ?
    here the link : http://jeanphiblog.media-box.net/dotclear/index.php?2009/12/05/330-flash-cs4-bitmapdata-bytearray-raw-format
    In the secon post i’ve noticed your link
    thanks
    JP

  4. sunnyon 06 Dec 2009 at 1:18 am

    JP, thanks for catching that – I have fixed the post : )

  5. Lorenzoon 28 May 2010 at 11:43 pm

    hello

    very interesting !

    in the article part “Saving To File”, you write a mistake : FileReference come with flash-player 9 (flash cs3)

  6. sunnyon 29 May 2010 at 1:14 am

    @Lorenzo, the FileReference class is available in FP9, but the save() method is available only for FP10+.

Trackback URI | Comments RSS

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word