Bitmap Basics
After i posted my last item on Perlin Noise in bitmaps, i realised that it wasn’t much help if you don’t know much about bitmaps, so here’s an introduction…
Why use Bitmap? Well for starters, Bitmaps render a lot quicker than Sprites, Shapes etc – not a problem if you only have 10 items on the stage but a big issue if you have hundreds or thousands of objects all moving around. Thats not to say you should always use bitmaps – they usually look awful when scaled for instance – but they definitely have their moments.
Simply put, the Bitmap class allows you to display images – either from the library, an external file or created programmatically. Before we look at how we do that, lets take a look at the class itself to see how it works.
var bmd:BitmapData = null; var pixelSnap:String = "auto"; var smooth:Boolean = false; var bm:Bitmap = new Bitmap(bmd, pixelSnap, smooth); addChild(bm);
bmd – this holds the actual image information.
pixelSnapping – whether to align the image with pixel boundaries (either “auto”, “always” or “never”).
smoothing – whether to smooth the image when it is scaled (true) or allow pixelation (false).
In this example, we create a new bitmap object (using the default parameters) and add it to the stage. If you run it, nothing seems to happen – thats because bitmapData (the image information) is set to null; the bitmap is on the stage but as it has zero width and height you can’t see it!
Adding something meaningful instead of null is what we want, so lets start by showing how to grab an image from the library and display that.
Displaying an image from the library
To add an image from the library at runtime is pretty easy. You just have to make a change to the properties of the image in the library to make it work.
First, create a new .fla file and import an image into the library by selecting file / import / import to library. Right-click on an image in the library to bring up the properties inspector.
Make sure that ‘Export for ActionScript’ and ‘Export in frame 1′ are both selected (if you can’t see them, try clicking on ‘Advanced’ to reveal more options). For ‘Class’, you can leave the default name or change it; either way, make a note of it because we’ll need it later.
In my example i have changed the name to ‘MyImage’ (there are restrictions on naming – you can only use the following characters: A-Z, a-z, 0-9 and underscore, and the first character can’t be a number). None of the other options need changing so leave them as they are for now.
When you click ‘OK’ a warning popup will appear – you can safely ignore that as we are not using the features it is warning us about – so click ‘OK’ again.
Now we can start coding. We’ll add the code to the timeline rather than in a seperate class, to keep it simple.
//grab a copy of the image from the library //using the Class name we assigned earlier var bmd:MyImage = new MyImage(); //create a Bitmap object and pass in the image information //in this and other examples, i won't bother with the pixelSnapping //and smoothing parameters for Bitmap - the default settings are fine var bm:Bitmap = new Bitmap(bmd); //add bitmap to the stage bm.x = 50; bm.y = 50; addChild(bm);
Pretty straight-forward if you ask me! Just change the two mentions of ‘MyImage’ to whatever Class name you gave the image in the library earlier. Here’s the result:
{BitmapExample1}
Now in this case it is obviously much easier just to drag the image from the library to the stage rather than messing about with properties and code – much less effort. The advantage of doing it this way is that you have much more control if you need it – e.g: tiling the image as a background.
Displaying an image from a file
If you’re loading an image at runtime, you need to use the Loader class to load your image. The details of the Loader class are beyond this introduction but there are plenty of good tutorials around if you want to know more, including a full example in the Adobe documentation.
Here’s a simple example. This time as a class rather than directly on the timeline:
package { import flash.display.Bitmap; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.net.URLRequest; [SWF(backgroundColor="#CCCCCC", frameRate="30", width="200", height="200")] public class BitmapExample2 extends Sprite { //store reference to loader object private var ldr:Loader; public function BitmapExample2() { //do some general housekeeping stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; //create a new loader object ldr = new Loader(); //create a url request object pointing to the image file to load var req:URLRequest = new URLRequest("image2.jpg"); //listen for the load complete event ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loadHandler); //start loading the image file ldr.load(req); } //called when image has loaded private function loadHandler(event:Event):void { //grab image from the loader //the image data is stored in the content property //we use "as Bitmap" so the compiler doesn't throw a compile time error in strict mode var bm:Bitmap = ldr.content as Bitmap; //add bitmap to stage bm.x = 50; bm.y = 50; addChild(bm); //remove listener from loader ldr.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadHandler); //delete loader object ldr = null; } } }
First, in the constructor we set up the Loader object and tell it to load the image. When the image has loaded, loadHandler(…) is called. In loadHandler, we create the bitmap object and add it to the stage. Lastly, we remove the listener from the loader object and set it to null. This allows garbage collection to remove the loader object as we don’t need it any more.
For this example it’s overkill, but it’s good to get into the habit of clearing up your unused listeners and objects – when you come to create something more complex it becomes a necessity. However, thats a whole other subject so i shouldn’t digress.
Note that when we grab the image from the loader object, we create the Bitmap object directly – ie: we dont have to create a seperate BitmapData object and pass it in as we did in the previous example. Again you now have full control over the image data to do something interesting with. Just one more situation to cover now…
Creating an image with code
To create a new bitmap from scratch, we just to create our own custom BitmapData object. We do it like this:
var w:uint = 100; var h:uint = 100; var transparent:Boolean = false; var colour:uint = 0xFF0000; var bmd:BitmapData = new BitmapData(w, h, transparent, colour);
w & h – width and height of the image. The maximum allowed values vary depending on which player you are targetting: for FP9 or AIR1.1 (or earlier) the maximum is 2880 for width or height. For FP10 and AIR1.5 onwards, the maximum is 8191 for width or height but with a further limit that width x height is less or equal to 16,777,215. E.g: for a width of 8191, the maximum height is 2048.
Setting transparent to true, clearly (ahem!) gives a transparent bitmap and the colour is the initial fill/background colour of the image in RGB (transparent = false) or ARGB (transparent = true).
In this example, we create a 100×100 bitmap:
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; [SWF(backgroundColor="#CCCCCC", frameRate="30", width="200", height="200")] public class BitmapExample3 extends Sprite { public function BitmapExample3() { //do some general housekeeping stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; //create a new BitmapData object var bmd:BitmapData = new BitmapData(100, 100, true, 0x80FFFF00); //create bitmap and pass in BitmapData object var bm:Bitmap = new Bitmap(bmd); //add bitmap to stage bm.x = 50; bm.y = 50; addChild(bm); } } }
Note that transparency is set to true so we use an ARGB format for the colour – alpha is set at 50% and RGB part set as yellow.
Doing something
Now that we have our bitmap object (and its underlying bitmapData property) we can manipulate pixels at will. We can apply filters or use drawing methods to change the image – this is will be the subject of my next post but for now i will leave you with a simple example of drawing on a bitmap with a rectangular fill:
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.geom.Rectangle; [SWF(backgroundColor="#CCCCCC", frameRate="30", width="200", height="200")] public class BitmapExample4 extends Sprite { public function BitmapExample4() { //do some general housekeeping stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; //create a new BitmapData object var bmd:BitmapData = new BitmapData(100, 100, false, 0x000000); //rectangle object points to area of bitmapdata to fill var rect:Rectangle = new Rectangle(0, 0, 100, 5); //keep looping until rect.y equals height of bitmapdata while (rect.y!=100) { //fill the area of bitmapdata signified by rect //with a random colour bmd.fillRect(rect, Math.random()*0xFFFFFF); //move rect down 5 rows rect.y += 5; } //create bitmap and pass in BitmapData object var bm:Bitmap = new Bitmap(bmd); //add bitmap to stage bm.x = 50; bm.y = 50; addChild(bm); } } }
{BitmapExample4}
Not exactly art, i know. Hopefully, when we get into filters next time, you’ll be more impressed. Until then, happy coding.
SOURCE CODE: Bitmap-Basics.zip