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
Post a comment
Name:


Email Address:


URL:


Comments:


Remember info?



Most Visited Entries
Experiments
Lectures
Contact
Backlog
In Love with
Powered by