Home >
Ah, BitmapData
Sometimes when we are working in Flash or Flex, we need to work with the raw pixels of an object on screen. Maybe we want to create a lightweight component to pull in photos off the web, make intelligently scaled and cropped thumbnails of them, and display them in a smoothly scrolling rectangle. Perhaps we have a character animation where the assets come from an artist on a Sprite Sheet.
Whatever the reason, often times we need to take pixels from one place and draw them somewhere else, with or without transformation or effects. This requires, at root, that you create a BitmapData to accept these pixels and use its methods to "suck in" the pixels from some other place and put those pixels onto itself. While this sounds easy, I've found that it's not always intuitive to get from A to B, so I thought I'd see if I could fill in some of the holes between the various bits of information I have been able to scrounge on this topic.
BitmapData vs. IBitmapDrawable
In order to understand how to use BitmapData for "pixel pushing," you need to understand IBitmapDrawable. As a quick refresher, if you see "I" in front of a Class name that was created by Adobe, that means that it's not actually a "class". but an Interface. There's some debate about whether this is appropriate, but it's a handy thing to know, especially in this case.
So what's an Interface?
I've talked about Interfaces before, but in a nutshell an Interface is a "contract" with a class. Essentially what it says is that when a Class implements an Interface, that methods defined by the Interface have to be defined in the Class. The programmer can then choose to make the implementation do anything that will fit the method signature. Interfaces can also define properties that all implementors must expose, but these have to be methods, which means that any properties defined in the Interface will need to be defined as getters and/or setters, and, again, the method implementation must adhere to the signature.
So, now that you understand that, take it and throw it out the window, preferably from several stories up. It won't help you understand BitmpaData, because in this case IBitmapDrawable appears to be what's known as a "marker interface." Which is a fancy way of saying, if it enforces any methods on its two implementors, these are not documented. That means that you and I have no way to do whatever it is that BitmapData does when it gets an IBitmapDrawable in an argument.
What implements IBitmapDrawable?
Two Classes implement IBitmapDrawable–BitmapData itself and DisplayObject. The good news is that these two classes will give you access to nearly every object you might want to copy pixels from. The bad news is that only one of the BitmapData methods (draw) takes an IBitmapDrawable as the source. All the rest, if they take a visual object at all, take only one Class–BitmapData.
It is actually possible to start out with a BitmapData in the first place, but in most cases you want to start out with an object that is a subclass of DisplayObject, such as MovieClip or Sprite. These are IBitmapDrawable, but not BitmapData objects (obviously).
How do I get from IBitmapDrawable to a BitmapData?
Sir Arthur Conan Doyle once said "How often have I said to you that when you have eliminated the impossible, whatever remains, however improbable, must be the truth?" And herein lies the answer of how to solve this problem. Only one method–draw–takes an IBitmapDrawable as one of its methods, so that's the method we use to translate from an IBitmapDrawable to a BitmapData if in fact we need to use some of the other methods. The draw() method is actually extremely powerful. With creative use of the other arguments, you can do most of the things that the other functions can do.
That being said, the other methods zero in on exactly what you're trying to do and make your code much easier to decipher, not to mention that it's easier to figure out yourself what you need to do to get the pixels you want and put them where you want. So, if you really need to use the other methods, you're going to have to come up with a BitmapData object from somewhere to use as the sourceBitmapData of the method you're trying to use for this BitmapData. That imples that you need not one BitmapData, but two–the one you're drawing on and the one you're drawing from. And we already know how to get pixels from an IBitmapDrawable onto a BitmapData, which is to use the draw() method. So, to get the pixels from a DisplayObject into any of the methods that take a BitmapData, you simply create an extra BitmapData and use the draw() method to get the pixels from the DisplayObject, and then that BitmapData can serve as the sourceBitmapData for the other methods.
This process seems like a bit of a hack to me, but it's the only possibility I see at this point. If you know of a way that "cuts out the middle man," please use the Comments field to clue me in.
How do I get an instance to refer to in ActionScript?
The process of getting instances of things is pretty straightforward in Flex, whether you create the instance in ActionScript or in MXML, so I'm going to focus on the process of creating the classes and getting references to them in Flash. This process doesn't seem to be detailed online anywhere, so I pretty much figured much of this out myself. Bear with me if some of the details are a bit off, and feel free to jump into the comments section if you know of a place where this is documented better.
BitmapData
It is possible to start out with a BitmapData, which seemed obvious to me after reading the 8BitRocket tutorial on tile sheet animation. Unfortunately, if the fla file was in the download for the tutorial, it didn't show up when I unzipped the file at my end, and so there was no way to see how the included png file became an instance of a custom Class that subclasses BitmapData. So here's how I make the translation from a graphic file to a BitmapData subclass.
First, open the File Menu. What you're looking for is "Import to Stage" or "Import to Library." If you want to have your BitmapData already on the stage for you to operate on, select "Import to Stage." If you intend to only instantiate your BitmapData through ActionScript, select "Import to Library." Don't worry if you select the wrong one, because you can change your mind by deleting the instance from the stage or creating an instance by dragging from the library.
In order to be able to reference this asset from ActionScript, you need to right click it in the library and select Properties>Export for Actionscript. Note that the Base class is flash.display.BitmapData. The class name will default to the name of the library symbol, which will probably be the original graphic file name. It's probably not a good idea to have a class name with a "." in it, so change it to something else.
If you want to have an instance defined on the stage already, be sure to give it an instance name. Be aware of what your "declare stage instances automatically" setting is (Publish Settings>Flash>Actionscript 3>Settings), because this will determine what you need to do to avoid getting errors when you refer to your instance. If this is checked, you want to avoid a statement like public var myTileSheet:BitmapData, whereas if it is unchecked, you must declare the variable (in strict mode). The advantage to unchecking this option is that if you're editing your code in a tool with code completion, such as FlashDevelop, then code completion will pop up with the options appropriate to BitmapData objects, because you've told FlashDevelop the type in the variable declaration. Be aware that this variable must be public. You can't "hide" instances that you let Flash put on stage for you by declaring them private or protected.
If your instance is not defined on stage, you can simply create a new one by a statement like public var myTyleSheet:BitmapData = new(MyTileSheet).
Whichever method you use, your shiny new MyTileSheet does not need to be on the Display List in order for you to use copyPixels(), draw(), or any of the other methods to copy its pixels onto the BitmapData you're preparing for display.
If you're wondering how all this plays out in Flex, the Embed statement will create the Class for you, and presumably the base class will be BitmapData. However, most of the things I've done in Flex with a Class defined this way, Flex has handled for me so I've never needed to look at that.
External Graphic File
If you have an external graphic fle or swf, use flash.display.Loader to load the asset. The main thing you need to remember is that you need to wait for the loader to dispatch a "complete" event to let you know that the load was finished. The "thing" that was loaded will be accessible through the loader's content property, which is of type DisplayObject.
MovieClip
MovieClip is probably the easiest one. You just define the MovieClip in the library, as you would normally do, then check "Export for ActionScript" and "Export in Frame 1" in the MovieClip properties. All the same caveats apply to where and how to declare the instance variable that I discussed for BitmapData.
Depending on what is going on inside your MovieClip, you may need to call stop() or goToAndStop() to make sure you're capturing the frame you want.
Sprite
This one was pretty puzzling for me, until I got some help from my "tweeps." You can't actually directly create a Sprite in the library. Instead, you create a MovieClip symbol, and when you "Export for ActionScript," change the Base class from MovieClip to Sprite. I'm not sure if you'd want to use this option to get a static asset to use as a BitmapData source, but it's a useful technique to know, and one I've never seen written down (except on Twitter).
Now What?
So we've figured out how to get our assets into the library. Now they're there, we know how to get a reference to them, and what we need to do to draw their pixels to a BitmapData. There's only one thing left to do, which is add it to the Display List. So don't forget to call addChild(myTileSheet), or you'll never see the fruits of your labor.
Related Links
Performance of copyPixels vs. Sprite Pooling
Utility Functions for DisplayObjects
CrossDomain Display Object Hack




Facebook Application Development
It's funny, I read your comments about there not being anything on the web that explains how to add a bitmap from the library and thought to myself - we'll everybody knows how to do that, surely it's widely documented.
But your right is as such as it's not very obvious in the Adobe docs - at least I couldn't quickly find it. And I wondered how did I learn how to do this - and of'course coming from as2, when AS3 came out I just tried to use the old loadBitmap method and it wasn't there - so I probably googled 'loadbitmap in as3' and found stuff like http://www.kirupa.com/forum/showthread.php?p=1919956
david
Cool link. Thanks :).
I kind of missed the transition of Flash to AS3 because I was busy learning Flex, so I'm having to play catchup as I take on more and more Flash IDE projects.