June 23, 2008
How to draw anything into a BitmapData properly

Looks like Eric has a little problem with getting a sprite with an non 0/0 registration point correctly drawn into a BitmapData object. Here's help. The problem is that by default the draw() command works in such a way that the registration point will line up with the upper left corner of the bitmapData. So what has to be done is to offset the sprite by the amount it's off from that point using the second argument which is a drawing matrix. You can retrieve a clips "real" registration point by using the getBounds() method. Feed the negative of the upper left corner into the drawing matrix and off you go:


function snapClip( clip:DisplayObject ):BitmapData
{
var bounds:Rectangle = clip.getBounds( clip );
var bitmap:BitmapData = new BitmapData( int( bounds.width + 0.5 ), int( bounds.height + 0.5 ), true, 0 );
bitmap.draw( clip, new Matrix(1,0,0,1,-bounds.x,-bounds.y) );
return bitmap;
}

So if you have a spirite named "testclip" on your stage, this will take a (non-scaled, non-rotated) bitmap snapshot of it:

var bitmap:BitmapData = snapClip( testclip );

Posted at June 23, 2008 05:10 PM | Further reading
Comments

Sweet! but how can i capture rotation/scaling too (I am running on ENTER_FRAME)

Posted by: ericd on June 23, 2008 05:28 PM

I'm pretty sure that by clever using the clip's transfrom.concatenatedMatrix there's a way to do this really nicely, but for a quick fix, just replace "clip" with "clip.parent" and it will hopefully work - but I'm really not sure if this works in any case, but at least in my quick test it seems to.

function snapClip( clip:DisplayObject ):BitmapData
{
var bounds:Rectangle = clip.getBounds( clip.parent );

var bitmap:BitmapData = new BitmapData( int( bounds.width + 0.5 ), int( bounds.height + 0.5 ), true, 0 );

bitmap.draw( clip.parent, new Matrix(1,0,0,1,-bounds.x,-bounds.y) );
return bitmap;
}

Posted by: Mario Klingemann on June 23, 2008 05:53 PM

Just as a quick tip, it's sometimes easier/more readable to do it like this:

var matrix=new Matrix();
matrix.translate(-bounds.x,-bounds.y);
/*maybe possitive numbers, don't remember ^^ */
bitmap.draw( clip.parent, matrix );

It is specially nicer when you work with rotation (Matrix.rotate()) and scale (Matrix.scale()) ^^
Oh, and remember to scale/rotate/translate the matrix in the correct order, or it will not work properly ;)

Posted by: Cay on June 24, 2008 10:38 PM

@cay: your way is slower + it's a good thing for everyone to be able to see that the Matrix constructor has some handy parameters.

Posted by: laz9 on June 27, 2008 07:26 PM

Alright, I figured out how to apply this to my situation, and in case anyone else has a similar setup, this may help.

In my situation, I had a bitmapData object the size of the stage and wanted to draw slash marks on it that were movieClips and were both scaled, rotated, and had a non-0 registration point. Assuming the bitmapData and bitmap objects are already setup and added to the stage, add this code:


var matrix:Matrix = new Matrix ();

matrix.scale (clip.scaleX, clip.scaleY);
matrix.rotate (clip.rotation * (Math.PI/180));
matix.translate (clip.x, clip.y);

stageBMD.draw (clip, matrix);


Note: the matrix.rotate function takes the angle in radians ( the * (Math.PI/180) converts the clips rotation to radians) - if you already have an angle in radians, don't convert it. Also, as Cay noted, make sure you keep the scale, rotate, translate in that order, or the positioning will get messed up when you rotate.

Hope this helped somebody - you guys sure helped me :)

Posted by: Greyson Parrelli on July 27, 2008 01:06 AM

Greyson - I didn't test it, but it looks like you could try stageBMD.draw (clip, clip.transform.matrix); as well

Posted by: Mario Klingemann on July 27, 2008 01:01 PM

not sure what to do with this now. plugged in the code but I get the following compiling errors:

The class or interface 'DisplayObject' could not be loaded.

Posted by: avery on October 8, 2008 06:25 AM

also,
The class or interface 'Rectangle' could not be loaded.

Posted by: on October 8, 2008 06:28 AM

Oh sorry, I forgot to mention: this is AS3 guys.

Posted by: Mario Klingemann on October 8, 2008 11:09 AM

as3 eh? damn. i'm working exclusively in as2 based on some other code i'm using. is there anyway, using your bitmap exporter code, to save multiple movie clips in the same jpg?

thanks again

Posted by: avery on October 8, 2008 03:20 PM

I had to figure this out on my own months ago when I created the SpringyTiles thing at the top of my blog. Each sprite had to be offset as I sliced up BitmapData from the image. It took a while. Wish I'd had this post back then. :-)

Posted by: polyGeek on November 8, 2008 07:29 PM

this is very useful for drawing movieclips on the stage...but how can i translate the x and y positions of a nested movieclip..?i've tried parent.parent and root too...but both these methods produce incorrect results...
please help me..

Posted by: ravi on August 19, 2009 12:53 PM

Wow, massive thanks to everyone who contributed on this post! I'm using it for generative art purposes.

Posted by: Fin on March 20, 2010 02:46 AM

AND my code is as follows(once you create a bitmap):

function drawIt(mcToDraw:DisplayObject):BitmapData {
var bounds:Rectangle = this.getBounds( mcToDraw );
bmp.draw( mcToDraw, mcToDraw.transform.matrix)
}

drawIt(myReallyNiceMC)

Just pass the MC you want it to draw! :D

Posted by: Fin on March 20, 2010 02:47 AM

I just spent 3-4 hours trying to figure this out. I'm still too angry to be truly thankful.

Posted by: on May 24, 2010 06:21 AM

this post saved my life. was really confused by the matrices, but this code really helped out, thanks!!

Posted by: shannon on January 25, 2011 07:17 PM

I came across this post looking for a way to grab a bitmap snapshot of an object as it appears on the stage, regardless of transforms applied in the display hierarchy to that object. This turned out to be much more difficult than I expected -- the solutions posted here are a good start for a single object's transformation but doesn't work when you have something crazy like:
- stage
- - container (rotated and scaled)
- - - another container (rotated and scaled)
- - - - object (you need to draw this)

Getting the bounds of 'object' on stage is easy via getBounds(stage), but drawing it to a BitmapData that matches those bounds has kept me up for several hours.

I think I finally got it:

function getBitmapData(object:DisplayObject):BitmapData {

var bounds:Rectangle = object.getBounds(stage);
var bmp:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x00000000);

var matrix:Matrix = object.transform.concatenatedMatrix;
var origin:Point = object.localToGlobal(new Point());
matrix.tx = origin.x - bounds.x;
matrix.ty = origin.y - bounds.y;

bmp.draw(object, matrix, object.transform.concatenatedColorTransform);

return bmp;
}

Hopefully that will help someone, or me when I lose track of this solution when I need it again and turn to google and end up here again. :)

Posted by: Aaron Beall on February 7, 2011 02:48 AM

Hay Man

You save my time :)

Thanks

Posted by: Ahmad Fathi Hadi on March 2, 2011 01:12 PM

thank you!

Posted by: michelle on May 10, 2011 09:56 PM

Situation:
I have a movieclip which I have adjusted the ".rotationZ" value.
This makes the movieclip.transform.matrix = null AND INSTEAD makes the movieclip have a matrix3D.

Using the
function getBitmapData(object:DisplayObject):BitmapData {

var bounds:Rectangle = object.getBounds(stage);
var bmp:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x00000000);

var matrix:Matrix = object.transform.concatenatedMatrix;
var origin:Point = object.localToGlobal(new Point());
matrix.tx = origin.x - bounds.x;
matrix.ty = origin.y - bounds.y;

bmp.draw(object, matrix, object.transform.concatenatedColorTransform);

return bmp;
} -From Aaron's post.


Will Throw an error b/c the 2D Matrix is null.
--> See "matrix.tx = origin.x - bounds.x;"

Goal:
Get 2D Bitmap For Collision Detection


Question :
Is it possible to make the 3D matrix back into 2D matrix... so I can make the BitMap?


Posted by: JGuy on October 10, 2011 06:03 AM

I must say... you saved my life! I was stuck with this part for about 3 days! Excellent job!

Posted by: Claudiu on October 10, 2011 06:22 PM
Post a comment
Name:


Email Address:


URL:


Comments:


Remember info?



Thank you!

Most Visited Entries
Sketches, Works & Source Code
Lectures
Contact
Backlog
In Love with
Powered by
Movable Type 2.661

© Copyright Mario Klingemann

Syndicate this site:
RSS 1.0 - RSS 2.0

Quasimondo @ flickr
Quasimondo @ LinkedIn
Quasimondo @ Twitter
Quasimondo @ Facebook
Quasimondo @ MySpace
Quasimondo is a Bright
Citizen of the TRansnational Republic
My other blog in german
Impressum


My family name is written Klingemann,
not Klingelmann, Klingeman, Klingaman, Kingemann,
Kindermann, Killingaman, Klingman, Klingmann, Klingonman
Klingemman, Cleangerman, Klingerman or Kleangerman

profile for Quasimondo at Stack Overflow, Q&A for professional and enthusiast programmers