Summary: Learn how to convert an image with a constant color background into an image with a transparent background. This involves the use of a technique commonly known as chroma key compositing.
This tutorial lesson is part of a series of lessons dedicated to object-oriented programming (OOP) with ActionScript.
Several ways to create and launch ActionScript programs
There are several ways to create and launch programs written in the ActionScript programming language. Many of the lessons in this series will use Adobe Flex as the launch pad for the sample ActionScript programs.
Getting started
An earlier lesson titled The Default Application Container provided information on how to get started programming with Adobe's Flex Builder 3.
The lesson titled Using Flex 3 in a Flex 4 World was added later to accommodate the release of Flash Builder 4. (See Baldwin's Flex programming website .)
You should study those lessons before embarking on the lessons in this series.
Some understanding of Flex MXML will be required
I also recommend that you study all of the lessons on Baldwin's Flex programming website in parallel with your study of these ActionScript lessons. Eventually you will probably need to understand both ActionScript and Flex and the relationships that exist between them in order to become a successful ActionScript programmer.
Will emphasize ActionScript code
It is often possible to use either ActionScript code or Flex MXML code to achieve the same result. Insofar as this series of lessons is concerned, the emphasis will be on ActionScript code even in those cases where Flex MXML code may be a suitable alternative.
I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.
I recommend that you also study the other lessons in my extensive collection of online programming tutorials. You will find a consolidated index at www.DickBaldwin.com .
In an earlier lesson titled Bitmap Basics , I explained the differences between Flex projects and ActionScript projects. I also introduced you to the classes named Bitmap and BitmapData .
The fundamentals of pixel processing
In the lesson titled Fundamentals of Image Pixel Processing , I showed you how to:
The organization of image information
In that lesson, I also explained how the color and transparency information for an image is stored in files and in the computer's memory. That included topics such as:
Creating a transparent background
In this lesson, I will show you how to convert an image with a constant color background (such as the top image in Figure 1) into an image with a transparent background (such as the bottom image in Figure 1) .
Chroma key compositing
This involves the use of a technique commonly known as chroma key compositing .
Here is a little of what Wikipedia has to say on the subject:
"Chroma key compositing (or chroma keying) is a technique for compositing two images or frames together in which a color (or a small color range) from one image is removed (or made transparent), revealing another image behind it.
This technique is also referred to as color keying, colour-separation overlay (CSO; primarily by the BBC[1]), greenscreen, and bluescreen.
It is commonly used for weather forecast broadcasts, wherein the presenter appears to be standing in front of a large map, but in the studio it is actually a large blue or green background. The meteorologist stands in front of a bluescreen, and then different weather maps are added on those parts in the image where the color is blue."
Commonly used in computer graphics
The process is also commonly used in computer graphics where it is desired to overlay one image onto another without letting the background color of the front image show.
That is the intent of this lesson, and the process developed here will be used in a future lesson on animation.
In this lesson, I will show you to start with an image having a solid background color, such as the top image in Figure 1 and how to convert that image into one with a transparent background, such as the bottom image in Figure 1.
| Screen output for the program named ChromaKey01. |
|---|
![]() |
A yellow Canvas object
Both images in Figure 1 are displayed on the same yellow Canvas object.
The color of the canvas is hidden by the magenta background color of the top image. However, that magenta background is totally transparent in the bottom image, allowing the yellow color of the canvas to show through.
The MXML file
The MXML file, shown in Listing 8, is no different from MXML files used to launch ActionScript programs in earlier lessons. Therefore, no explanation of the MXML code is warranted.
Will explain in fragments
I will explain the ActionScript code for the program named ChromaKey01 in fragments. A complete listing of the code for the ActionScript class named Driver is provided in Listing 7.
The processChromaKey method
This program illustrates the use of a custom method named processChromaKey . This method scans all of the pixels in an incoming bitmap and identifies those pixels with a color of pure magenta. The alpha values for the magenta pixels are set to zero to make them transparent. Then the bitmap is modified accordingly.
The method can easily be modified to accommodate an image background of any solid color such as green or blue. Note however, that magenta is commonly used in computer graphics, and is often referred to as "magic pink."
Beginning of the ActionScript class named Driver
The Flex code in Listing 8 instantiates a new object of the class named Driver and adds that object to the display list as a child of the Application container.
The ActionScript code for the class named Driver begins in Listing 1.
package CustomClasses{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
import mx.containers.Canvas;
import mx.controls.Image;
import mx.events.FlexEvent;
//====================================================//
public class Driver extends Canvas {
private var origImage:Image = new Image();
Extend the Flex Canvas class
Note that the Driver class extends the Flex Canvas class, thus making it possible to add other objects as children of an object of the Driver class.
Another reason for extending the Canvas class
I could have accomplished that purpose by extending any number of Flex container classes. However, an important characteristic of the Canvas class for this application is the ability to specify the physical locations of the child objects in absolute coordinates. Few if any other Flex containers allow you to do that,
The constructor
The constructor for the Driver class is shown in its entirety in Listing 2.
public function Driver(){//constructor
//Make this Canvas visible with a yellow background.
setStyle("backgroundColor",0xFFFF00);
setStyle("backgroundAlpha",1.0);
//Load the file mage and embed it in the swf file.
//Note the slash that is required by FlashDevelop.
[Embed("/dancer.png")]
var img:Class;
origImage.load(img);
//Register a CREATION_COMPLETE listener
this.addEventListener(FlexEvent.CREATION_COMPLETE,
completeHandler);
} //end constructor
Make the canvas visible
The constructor begins by setting two style properties on the Canvas object to make it yellow and opaque.
You learned how to set styles on objects in ActionScript code as early as the lesson titled What is OOP and Why Should I Care?
Load the image from the file
Then the constructor loads the image from the image file named dancer.png and embeds it in the swf file. You learned how to do this as early as the lesson titled Inheritance - The Big Picture.
No lossy compression allowed
Note that this program uses an image from a png file for demonstration purposes.
Unlike a jpg file, (which uses lossy compression) the colors that you extract from a png file are exactly the colors that were stored in the png file. That is a requirement for a chroma key process that is based on an exact color match.
An unusual requirement
There is an unusual requirement shown in Listing 2 that you haven't seen in the earlier lessons in this series.
This is the first lesson that I have written explaining a program that loaded and embedded an image file where the program was developed using FlashDevelop (see Publication Issues below).
File organization
In this case, the image file was placed in the same folder as the MXML file. Note that it was necessary for me to precede the name of the image file in Listing 2 with a slash character. I have not previously encountered that requirement when using Flex Builder 3. (Note however that inclusion of the slash character in a Flex Builder 3 project doesn't seem to cause a problem.)
Register a CREATION_COMPLETE listener
Finally, Listing 2 registers an event handler to handle CREATION_COMPLETE events fired by the Canvas object.
You learned how and why to use a CREATION_COMPLETE listener in the earlier lesson titled Encapsulation - The Big Picture.
The CREATION_COMPLETE event handler
The CREATION_COMPLETE event handler is shown in its entirety in Listing 3. This method is executed when the Canvas object has been fully created.
private function completeHandler(
event:mx.events.FlexEvent):void{
//Get and save a reference to a Bitmap object
// containing the contents of the origImage file.
var origBitMap:Bitmap = Bitmap(origImage.content);
//Set the width and height of the Canvas object
// based on the size of the origBitMap bitmap. Make
// ten pixels wider and twice as high as the
// bitmap.
this.width = origBitMap.width + 10;
this.height = 2*origBitMap.height;
//Add the original image to the Canvas object at
// the default location of 0,0.
this.addChild(origImage);
//Clone the origBitMap to create a
// duplicate.
var dupBitMap:Bitmap = new Bitmap(
origBitMap.bitmapData.clone());
//Put the dupBitMap in a new Image object and
// place it on the canvas below the original image.
dupBitMap.x = 0;
dupBitMap.y = origBitMap.height;
var newImage:Image = new Image();
newImage.addChild(dupBitMap);
this.addChild(newImage);
//Set the alpha value for all pixels in the new
// image with a color of pure magenta to zero.
processChromaKey(dupBitMap);
} //end completeHandler
The call to the method named processChromaKey
With the exception of the call to the method named processChromaKey at the end of Listing 3, I explained everything in Listing 3 in the earlier lesson titled Fundamentals of Image Pixel Processing. I won't waste your time by repeating that explanation here.
Beginning of the processChromaKey method
The processChromaKey method begins in Listing 4.
private function processChromaKey(bitmap:Bitmap):void{
//Get the BitmapData object.
var bitmapData:BitmapData = bitmap.bitmapData;
//Populate a one-dimensional byte array of pixel
// data from the bitmapData object. Note that the
// pixel data format is ARGB.
var rawBytes:ByteArray = new ByteArray();
rawBytes = bitmapData.getPixels(new Rectangle(
0,0,bitmapData.width,bitmapData.height));
A reference to a Bitmap object
This method receives a reference to a Bitmap object as an incoming parameter.
It identifies all of the pixels in the incoming bitmap with a pure magenta color and sets the alpha bytes for those pixels to a value of zero.
This causes those pixels to become transparent as shown by the bottom image in Figure 1.
Nothing new in Listing 4
I explained all of the code in Listing 4 in the earlier lesson titled Fundamentals of Image Pixel Processing.
The ByteArray object is populated with pixel data
When the getPixels method returns in Listing 4, the pixels from a rectangular region that encompasses the entire bitmap are stored in the ByteArray object referred to by rawBytes .
The organization of the pixel data
The array is populated with the bitmap pixel data from the rectangular region on a row by row basis.
The first four bytes in the array belong to the pixel in the upper-left corner of the rectangular region. The next four bytes belong to the pixel immediately to the right of that one, and so on.
Four bytes per pixel
Each set of four bytes represents one pixel in ARGB format. In other words, the first byte in the four-byte group is the alpha byte. That byte is followed by the red byte, the green byte, and the blue byte in that order.
This information is critical when time comes to use the data in the array to modify the bitmap data.
Set selected alpha values to zero
The code in Listing 5 iterates through the entire set of image pixels and sets selected alpha values to zero.
//Declare working variables. Note that there is
// no requirement to deal with the green color
// value in this case of testing for magenta.
var cnt:uint;
var red:uint;
var green:uint;
var blue:uint;
for (cnt = 0; cnt < rawBytes.length; cnt += 4) {
//alpha is in rawBytes[cnt]
red = rawBytes[cnt + 1];
green = rawBytes[cnt + 2];
blue = rawBytes[cnt + 3];
if ((red == 255) && (green == 0 ) &&
(blue == 255)) {
//The color is pure magenta. Set the value
// of the alpha byte to zero.
rawBytes[cnt] = 0;
}//end if
}//end for loop
A for loop
After declaring some working variables, Listing 5 iterates through all of the data in the ByteArray object. It extracts the red, green, and blue color bytes from each four-byte group and tests to see if red and blue are both set to full intensity with a value of 255 and green is set to zero.
If true, this is interpreted to match the magenta background color, and the value of the alpha byte in that four-bit group is set to zero.
Store the modified pixel data in the bitmap
Listing 6 copies the modified pixel data from the ByteArray object back into the bitmap, overwriting the pixel data previously stored in the bitmap.
//Put the modified pixels back into the bitmapData
// object.
rawBytes.position = 0;//this is critical
bitmapData.setPixels(new Rectangle(
0,0,bitmapData.width,bitmapData.height),
rawBytes);
} //end processChromaKey method
//--------------------------------------------------//
} //end class
} //end packageI explained all of the code in Listing 6 in the earlier lesson titled Fundamentals of Image Pixel Processing.
The end of the class
Listing 6 also signals the end of the method, the end of the class, the end of the package, and the end of the program.
I encourage you to run this program from the web. Then copy the code from Listing 7 and Listing 8. Use that code to create a new project. Compile and run the project. Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.
I will publish a list containing links to ActionScript resources as a separate document. Search for ActionScript Resources in the Connexions search box.
Complete listings for the program discussed in this lesson are provided in Listing 7 and Listing 8 below.
/*Project ChromaKey01
This project scans all of the pixels in an image to
identify those pixels with a color of pure magenta. The
alpha value for those pixels is set to zero to make them
transparent.
*********************************************************/
package CustomClasses{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
import mx.containers.Canvas;
import mx.controls.Image;
import mx.events.FlexEvent;
//====================================================//
public class Driver extends Canvas {
private var origImage:Image = new Image();
public function Driver(){//constructor
//Make this Canvas visible with a yellow background.
setStyle("backgroundColor",0xFFFF00);
setStyle("backgroundAlpha",1.0);
//Load the origImage and embed it in the swf file.
//Note the slash that is required by FlashDevelop.
[Embed("/dancer.png")]
var img:Class;
origImage.load(img);
//Register a CREATION_COMPLETE listener
this.addEventListener(FlexEvent.CREATION_COMPLETE,
completeHandler);
} //end constructor
//--------------------------------------------------//
//This handler method is executed when the Canvas has
// been fully created.
private function completeHandler(
event:mx.events.FlexEvent):void{
//Get and save a reference to a Bitmap object
// containing the contents of the origImage file.
var origBitMap:Bitmap = Bitmap(origImage.content);
//Set the width and height of the Canvas object
// based on the size of the origBitMap bitmap. Make
// ten pixels wider and twice as high as the
// bitmap.
this.width = origBitMap.width + 10;
this.height = 2*origBitMap.height;
//Add the original image to the Canvas object at
// the default location of 0,0.
this.addChild(origImage);
//Clone the origBitMap to create a
// duplicate.
var dupBitMap:Bitmap = new Bitmap(
origBitMap.bitmapData.clone());
//Put the dupBitMap in a new Image object and
// place it on the canvas below the original image.
dupBitMap.x = 0;
dupBitMap.y = origBitMap.height;
var newImage:Image = new Image();
newImage.addChild(dupBitMap);
this.addChild(newImage);
//Set the alpha value for all pixels in the new
// image with a color of pure magenta to zero.
processChromaKey(dupBitMap);
} //end completeHandler
//--------------------------------------------------//
//This method identifies all of the pixels in the
// incoming bitmap with a pure magenta color and sets
// the alpha bytes for those pixels to a value of
// zero.
private function processChromaKey(bitmap:Bitmap):void{
//Get the BitmapData object.
var bitmapData:BitmapData = bitmap.bitmapData;
//Populate a one-dimensional byte array of pixel
// data from the bitmapData object. Note that the
// pixel data format is ARGB.
var rawBytes:ByteArray = new ByteArray();
rawBytes = bitmapData.getPixels(new Rectangle(
0,0,bitmapData.width,bitmapData.height));
//Declare working variables. Note that there is
// no requirement to deal with the green color
// value in this case of testing for magenta.
var cnt:uint;
var red:uint;
var green:uint;
var blue:uint;
for (cnt = 0; cnt < rawBytes.length; cnt += 4) {
//alpha is in rawBytes[cnt]
red = rawBytes[cnt + 1];
green = rawBytes[cnt + 2];
blue = rawBytes[cnt + 3];
if ((red == 255) && (green == 0 ) &&
(blue == 255)) {
//The color is pure magenta. Set the value
// of the alpha byte to zero.
rawBytes[cnt] = 0;
}//end if
}//end for loop
//Put the modified pixels back into the bitmapData
// object.
rawBytes.position = 0;//this is critical
bitmapData.setPixels(new Rectangle(
0,0,bitmapData.width,bitmapData.height),
rawBytes);
} //end processChromaKey method
//--------------------------------------------------//
} //end class
} //end package
<?xml version="1.0" encoding="utf-8"?>
<!--
Project ChromaKey01
This project scans all of the pixels in an image to
identify those pixels with a color of pure magenta. The
alpha value for those pixels is set to zero to make them
transparent.
-->
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:cc="CustomClasses.*">
<cc:Driver/>
</mx:Application>This section contains a variety of miscellaneous materials.
-end-