Flash/AS3 - MovieClip into Bitmap - actionscript-3

I need to turn a MovieClip that I have on the stage into a Bitmap. The function I have made for this halfway works; it does make a Bitmap from the MovieClip with the correct image, but it does not rotate it.
Here is the function
function makeBitmapData(mov):BitmapData
{
var bmpData:BitmapData = new BitmapData(mov.width, mov.height, true, 0);
bmpData.draw(mov);
this.addChild(new Bitmap(bmpData)); //Shows the bitmap on screen purely for example
return bmpData;
}
Here is the output
How should I rotate the bitmap or just purely copy all the pixels in that bitmap, rotated and all?

Have you checked rotate() function and fl.motion.MatrixTransformer class? Also this question looks helpful.

In the function that implements your code.
var b:Bitmap = new Bitmap ( makeBitmapData(mov) );
addChild(b);
b.rotation = mov.rotation;

One way to accomplish this, is to draw from the items parent instead, that way any transformation/filters will be reflected in the bitmap data captured. So something like this:
function makeBitmapData(mov:DisplayObject):BitmapData
{
var rect:Rectangle = mov.getBounds(mov.parent); //get the bounds of the item relative to it's parent
var bmpData:BitmapData = new BitmapData(rect.width, rect.height, false, 0xFF0000);
//you have to pass a matrix so you only draw the part of the parent that contains the child.
bmpData.draw(mov.parent, new Matrix(1,0,0,1,-rect.x,-rect.y));
addChild(new Bitmap(bmpData)); //Shows the bitmap on screen purely for example
return bmpData;
}

Related

Preventing the bounding box of transparent Bitmap Sprite from triggering mouse events

I thought I had solved my mouseEvent problem for Sprites containing a Bitmap with an alpha channel but I've encountered a new issue shown in the image below: the bounding box of the "Eurasia" map Sprite is triggering a `MouseEvent.Roll_Out" for the "Africa" Sprite.
My setup: Each map piece is a Sprite with a child Bitmap (PNG with alpha) and a "hitArea" Sprite derived from the Bitmap. The relevant code is below. This works great – except in the case where there are bounding box overlaps. The eventListeners I attach to each Sprite use MouseEvent.ROLL_OVER and MouseEvent.ROLL_OUT but I have also tried MouseEvent.MOUSE_OVER and MouseEvent.MOUSE_OUT.
I've tried attaching eventlisteners to the "hitArea" Sprite and various other things but I can't get the bounding box to be ignored. Are there any settings I may have missed – or a workaround?
Code:
buttonImage = new Bitmap(upImageData);
buttonImage.smoothing = true;
this.addChild(buttonImage);
hitSprite = createHitArea(upImageData, 4);
this.addChild(hitSprite);
hitSprite.visible = false;
hitSprite.mouseEnabled = false;
this.hitArea = hitSprite;
public function createHitArea(bitmapData:BitmapData, grainSize:uint=1):Sprite
{
var _hitarea:Sprite = new Sprite();
_hitarea.graphics.beginFill(0x000000, 1.0);
for(var x:uint=0;x<bitmapData.width;x+=grainSize) {
for(var y:uint=grainSize;y<bitmapData.height;y+=grainSize) {
if(x<=bitmapData.width && y<=bitmapData.height && bitmapData.getPixel(x,y)!=0) {
_hitarea.graphics.drawRect(x,y,grainSize,grainSize);
}
}
}
_hitarea.graphics.endFill();
_hitarea.cacheAsBitmap = true;
return _hitarea;
}
If using a vector mask is not a viable option (it should work if you changed your hitSpite into a Shape and then made it the mask of the map piece sprite - also you'd have to add it as a sibling of the map piece and not a child), then the way most people do this is checking if the pixel under the mouse is transparent or not.
Here is an example:
Let's say all your map pieces are the sole children of a Sprite referenced in a var called container. Let's also make the assumption for the example, that your map pieces are all Sprites that have the png Bitmap as the bottom most child.
You need to add the click listener to the container (instead of each individual map piece):
container.addEventListener(MouseEvent.CLICK,click);
function click(e:MouseEvent):void {
var child:Sprite; //a helper var to store the current iterations child below in the while loop
var target:Sprite; //the item that we determined was clicked
//iterate through all children of container (backwards, so we process the top most layer first)
var i:int = container.numChildren;
while(i--){
child = container.getChildAt(i) as Sprite; //populate the child var
//now we check if the mouse is over this child by a simple hit test point
//we also then check if the pixel under the mouse is transparent (a value of 0)
if(child.hitTestPoint(e.stageX, e.stageY) && Bitmap(child.getChildAt(0)).bitmapData.getPixel32(child.x + e.localX,child.y + e.localY)){
target = child;
break; //break out of the loop since we found a child that meets the criteria
}
}
trace(target);
//now do something with target
}

Converting a Shape to a Bitmap

I have created a subclass of Shape that contains paired GraphicsPath and GraphicsStroke objects. The class has a public method for retrieving the shape as a bitmap for passage to a Pixelbender kernel - the method is as follows:
public function GetBitmap():Bitmap{
var bmpData:BitmapData = new BitmapData(this.width, this.height, true, 0x00FFFFFF);
bmpData.draw(this);
return new Bitmap(bmpData);
}
To test these, I have the following code:
var v:Vector.<Number> = new <Number>[10,10,50,10,50,50]; //defines GraphicsPath.data to be used
var wave:CustomWave = new CustomWave(v,0xff0000); //constructor for the subclass
wave.Refresh(); //clears the Shape and redraws the GraphicsPath
//adds as shape
addChild(wave);
//adds as bitmap
var bmp:Bitmap = wave.GetBitmap()
addChild(bmp);
The visual output from both:
Any idea what could be causing the difference?
It's a long story, how to work with width and height, if you don't want any problems, draw your path from (0,0) or you can modify your function:
public function GetBitmap():Bitmap {
var bounds: Rectangle = getBounds(this);
var bmpData:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0);
bmpData.draw(this, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y));
return new Bitmap(bmpData);
}
It may have something to do with the registration point of the Shape you're drawing into the Bitmap. Any chance you draw stuff above or to the left of the 0,0 coordinates? Then you'd have to add some params (perhaps a transformation Matrix) to the draw call, to get the right offset and such.

Drawing a bitmap based on a transformed movieclip

I'm drawing bitmaps of movieclips which I then feed into my hittest function to test for collisions. However, I'm not quite sure how i would add to the code below to take into account and draw bitmaps for movieclips which have been scaled and/or rotated. The below code obviously only works for non-transformed movieclips. I've included in comments code which i've already tried but to no success.
When adding the drawn bitmap to the stage, no matter whether the movieclip in question is transformed or not, the drawn bitmap is "cut off" and incorrectly drawn - it appears to only draw a section of it. However, this does not particularly affect the collision testing for the non-transformed movieclips, but has an adverse effect on transformed movieclips.
All of the movieclips I want to be drawn have been created through the graphics property.
//for example:
var mymc:MovieClip = new MovieClip();
var g:Graphics = mymc.graphics;
g.moveTo(0,0);
g.lineTo(17.5,0);
g.lineTo(8.75,17.5);
g.lineTo(-8.75,17.5);
g.lineTo(0,0);
main code:
for each(var mc:MovieClip in impassable) {
//var bMatrix:Matrix = new Matrix();
//bMatrix.scale(mc.scaleX, mc.scaleY);
//bMatrix.rotate(mc.rotation * (Math.PI/180));
var bData:BitmapData = new BitmapData(mc.width, mc.height, true, 0);
//bData.draw(mc, bMatrix);
bData.draw(mc);
var bitmap:Bitmap = new Bitmap(bData);
bitmap.x = mc.x;
bitmap.y = mc.y;
var HitTest:Number = newCollision(bitmap, centerX, centerY, 13.7);
Any thoughts? thanks
This function will create a BitmapData clone of a DisplayObject, taking into account its transform matrix, though it doesn't take into account bitmap filters. (Based on this answer.)
function createBitmapClone(target:DisplayObject):BitmapData {
var targetTransform:Matrix = target.transform.concatenatedMatrix;
var targetGlobalBounds:Rectangle = target.getBounds(target.stage);
var targetGlobalPos:Point = target.localToGlobal(new Point());
// Calculate difference between target origin and top left.
var targetOriginOffset:Point = new Point(targetGlobalPos.x - targetGlobalBounds.left, targetGlobalPos.y - targetGlobalBounds.top);
// Move transform matrix so that top left of target will be at (0, 0).
targetTransform.tx = targetOriginOffset.x;
targetTransform.ty = targetOriginOffset.y;
var cloneData:BitmapData = new BitmapData(targetGlobalBounds.width, targetGlobalBounds.height, true, 0x00000000);
cloneData.draw(target, targetTransform);
return cloneData;
}
When you call successive transforms on a Matrix, the ordering is very important and can really mess things up.
Luckily there is a helper method that allows you to specify translation, rotation and scaling in one go and avoid those issues - createBox
For your case, something like this:
var matrix:Matrix = new Matrix();
matrix.createBox(mc.scaleX, mc.scaleY, mc.rotation*Math.PI/180, 0, 0);
(the two zeros are for x and y translation)

AS3/FLEX - how to convert Sprite graphics into bytes

I wrote application that lets people paint together via internet (using Adobe cirrus). Everything works great but when for example I run my application and paint something before my friend connects, he dont see that what I have painted. So I'm looking for the method, that would let me convert my canvas into something(object) that it is possible to send by internet (I cant send whole Sprite, it's not possible to copy its graphics on the friend's application, it's null).
So let's get this clear. The main question is: How to convert graphic's of Sprite into object, that would let me convert it back to Sprite and copy its canvas.
ANSWER:
I used DisplayConverter library from "www.Flextras.com" post with his mod to convert Sprite to BitmapData and then to ByteArray and it works. I couldn't receive BitmapData on the friend's app, but It worked with ByteArray.
Sprite -> BitmapData -> ByteArray;
ByteArray -> BitmapData -> Sprite;
//TO SEND
var bitmapdata:BitmapData = DisplayConverter.spriteToBitmapData(palette);
var bytearr:ByteArray = bitmapdata.getPixels(bitmapdata.rect);
//TO RECEIVE
var bmd:BitmapData = new BitmapData(530,430);
bmd.setPixels(bmd.rect, bytearr);
mysprite.graphics.beginBitmapFill(bmd);
mysprite.graphics.drawRect(0,0,530,430);
mysprite.graphics.endFill();
Hope this will help someone
I think you want to convert your Canvas into a BitMap or BitMapData (and back). A Flex Canvas extends Sprite, so you can use a library like this one. To copy the relevant code, this will convert a Sprite to a BitMap:
public static function spriteToBitmap(sprite:Sprite, smoothing:Boolean = false):Bitmap
{
var bitmapData:BitmapData = new BitmapData(sprite.width, sprite.height, true, 0x00FFFFFF);
bitmapData.draw(sprite);
return new Bitmap(bitmapData, "auto", smoothing);
} // END FUNCTION spriteToBitmap
This will convert a Bit Map to a Sprite:
public static function bitmapToSprite(bitmap:Bitmap, smoothing:Boolean = false):Sprite
{
var sprite:Sprite = new Sprite();
sprite.addChild( new Bitmap(bitmap.bitmapData.clone(), "auto", smoothing) );
return sprite;
} // END FUNCTION bitmapToSprite
In my own development, I have a mod to this library, which allows me to get the BitMapData instead of an actual BitMap. So, this will turn a Sprite into BitMapData:
public static function spriteToBitmapData(sprite:Sprite):BitmapData
{
var bitmapData:BitmapData = new BitmapData(sprite.width, sprite.height, true, 0x00FFFFFF);
bitmapData.draw(sprite);
return bitmapData;
} // END FUNCTION spriteToBitmapData
This will take BitMapData and turn it back into a Sprite:
public static function bitmapDataToSprite(bitmapData:BitmapData, smoothing:Boolean = false):Sprite
{
var sprite:Sprite = new Sprite();
sprite.addChild( new Bitmap(bitmapData.clone(), "auto", smoothing) );
return sprite;
} // END FUNCTION bitmapToSprite
You do want to keep in mind that when converting the BitMap or BitMapData back into a Sprite you will probably not be able to cast it as a Canvas. For information on sending BitMapData to a server; look at this question.
A better approach is, instead of going directly to pixels, have the user gestures create data, then reflect that data as a drawing on your canvas. Transmit the same data to the other user and he/she will get the same drawing.

AS3 loading image from Array into empty movieclip

I have tried this to load image path from database via php and load the image in flash. Now how can i add child to every single image to a every single empty movie clip for the farther use. the code is
var ldr:URLLoader = new URLLoader(new URLRequest("m_shirts.php"));
ldr.addEventListener(Event.COMPLETE, _done);
function _done(e:Event):void {
ldr.removeEventListener(Event.COMPLETE, _done);
var ar:Array = String(e.target.data).split("#");
for (var x:int=0; x<ar.length; x++){
/*var img:Loader = new Loader();
img.load(new URLRequest(ar[x]));
shirts.addChild(img);*/
var myLoader:Loader = new Loader();
var my_mc:MovieClip = new MovieClip();
myLoader.load(new URLRequest(ar[x]));
my_mc.addChild(myLoader);
addChild(my_mc);
my_mc.x= my_mc.width + 50;
}
}
Ok, I will try to answer this from what I understand:
You simply cannot convert Loader instances to a MovieClip. A Loader is a Loader and a MovieClip is a MovieClip, much like an Array is an Array or a Function is a Function. Their common base class is DisplayObjectContainer. It has most of the functionality MovieClips have except for child manipulation (although the methods are there) and drawing API as per the graphics property.
You can access the size of the loaded image by reading the Loader's width and height.
Your problem seems to be, that you want to determine the image's size before it is loaded. You cannot do that. You have to wait for it to load first. The contentLoaderInfo will dispatch an Event.COMPLETE when the image is available.