An alternative to bitmap transparency in Flash
Posted by Will | Filed under Adobe Flash, Adobe Flex, Banners, Experiments, Tutorials
When it comes to using transparent bitmap images in Flash often you will find using a PNG is your best option. However, a major caveat with using PNG images is the significant increase in file size compared to non-transparent image types such as JPEGs and (non-transparent) GIFs. This often becomes an issue when working on projects with limited allocated file size, such as banner ads.

A transparent PNG of the above image has a file size of approximately 109kB
Lately I’ve been toying with an alternative to PNGs… using JPEGs. “Wait a minute…”, you say, “JPEGs don’t support transparency!”. That’s correct but by making use of Flash’s BitmapData class we can merge two non-transparent images together to make a single transparent image. Even though this method actually requires 2 separate JPEGs the total combined file size is almost always significantly smaller than a single PNG!
Understanding channels
Bitmap images are made up of 3 separate colours, red, green and blue. Transparent images are special as they contain a forth channel called an alpha channel. Our challenge here is to create this forth channel for our image. But how?
The solution is to use two images of the same subject. One is our source image (on the left) the other our mask image (on the right). Using Photoshop I have output our source image on a coloured background and our mask image in a high-contrast inverted black and white. The important thing to note there is that even though our mask image appears black and white it still contains red, green an blue channels.

The above 2 JPEGs have a combined file size of only 29kB
How these two images are loaded is really up to you. Whether they are compiled into your application or loaded at runtime doesn’t really matter. What matters is we have access to both our source image and mask image’s BitmapData object. As this is a somewhat advanced topic I am assuming you know how to either dynamically load images or instantiate compiled objects.
Channel copying
We must create a new BitmapData instance which we will copy our source image to. We do this as we need our BitmapData object to contain an alpha channel. By default BitmapData objects are constructed with transparency set to true so we only need to pass the dimensions our new image needs to be. For this we simply use the same dimensions as our source image as we will be doing a straight copy of it. To copy our source image we use the copyPixels method of the BitmapData class.
// sourceBMD is our source image's BitmapData object var bmd:BitmapData = new BitmapData(sourceBMD.width, sourceBMD.height); bmd.copyPixels(sourceBMD, sourceBMD.rect, new Point());
Once we’ve copied our source image to the new transparency-ready BitmapData object we now copy any of the 3 available channels of our mask image to the alpha channel of our new BitmapData object. I say ANY as it really shouldn’t matter which channel you choose however I find copying the red channel of the mask image usually provides the best results. We use the copyChannel method of the BitmapData class to do this.
// maskBMD is our mask image's BitmapData object bmd.copyChannel(maskBMD, maskBMD.rect, new Point(), BitmapDataChannel.RED, BitmapDataChannel.ALPHA); var bm:Bitmap = new Bitmap(bmd); addChild(bm);
Once this is done you should have a transparent image created from 2 non-transparent images! At this point you are free to dispose of your source and mask BitmapData objects as they are no longer needed.
The resulting combined image.
As you can see the resulting image is a fairly convincing alternative to using a single file-size heavy PNG. If you’re wondering why our source image is on a dark green background it is because this is needed for our alpha channel to blend against. I’ve chosen a neutral colour similar to the subject. If the background was simply white you will likely see a faint white outline around the images as our alpha layer blends against the other 3 channels.
To simplify this already simple process I have created a custom class called ChannelMergedBitmapData which extends BitmapData and handles the above process for you. You simply pass the source and mask BitmapData objects and it does the rest.
var bmd:BitmapData = new ChannelMergedBitmapData(sourceBMD, maskBMD); var bm:Bitmap = new Bitmap(bmd); addChild(bm);
You are welcome to download the class here.




December 25th, 2009 at 2:21 am
Make your transparent pngs in Fireworks by exporting the png rather than saving the native png format in Fireworks or making any sort of png in Photoshop. You’ll find that your file size is not significantly different than a jpg.
December 25th, 2009 at 5:33 am
Good insight Will. Correct me if I’m wrong, but I think this has been a feature of the Flash IDE for quite some time (Flash MX could do it). In Flash Pro, you can import a PNG into the library and set the compression to JPEG. The image will keep its transparency.
This feature was supposedly also implemented in a recent version of Flex, but I have not yet tested it.
December 25th, 2009 at 7:47 am
Amy, the example image shown is exported as a 24bit PNG using Photoshop’s save for web feature.
December 25th, 2009 at 7:52 am
Nicolas,
Yes you are correct. This method probably won’t replace using PNG’s in 99% of cases. To be honest I haven’t needed to use it in any projects as of yet. This method would probably only be used when needing to load your transparent image at runtime vs using an embedded pre-jpegified bitmap. Thanks for your comment.
December 28th, 2009 at 1:16 pm
interesting..nice work…