To check whether Movie Clip got filled at one place - actionscript-3

I have created a empty movie clip .
And i,m brushing on that .(i.e)Filling(Begin Fill) it with ellipse for every click .
How do I check whether it is filled at particular place .(say 400 x 400 from x=0,y=0)?

First you would need to convert it to a bitmapdata format.
Then you would use the function getPixel to query it.
import flash.display.Bitmap;
import flash.display.BitmapData;
// Lets say drawingpad is a MovieClip that is getting ellipses drawn on it.
var bitmap:Bitmap = new Bitmap(new BitmapData(stage.stageWidth,stage.stageHeight));
bitmap.draw(drawingpad);
var value:uint = bitmap.bitmapData.getPixel(400,400);
Hope this helps

I assume with "400 x 400 from x=0,y=0" you mean a the area between 0,0 and 400,400.
You need to copy the content of the rectangle of your MovieClip to a Bitmap, to be able to get information about its pixels.
// coordinates as in the question's example, could be method parameters
var x1:int=0;
var y1:int=0;
var x2:int=400;
var y2:int=400;
// bitmap with transparency, with a size of the rectangle to check
var bitmap:Bitmap = new Bitmap(new BitmapData(x2-x1, y2-y1, true, 0x00000000));
// draw the painted mc to the bitmap, displaced to upper left x and y
bitmap.draw(mc, new Matrix(1,0,0,1,-x1,-y1)));
Using getColorBoundsRect, you can check if a bitmap contains a colour, or if it contains any other colours. Now check if it contains any other colour than 'transparent' (= any other colours with an alpha value>0):
var maskColor:uint = 0xFF000000; // ignore rgb, only check alpha values
var color:uint = 0x00000000; // 'empty', fully transparent color
// get a rect containing all pixels with not fully transparent colors
var colorBoundsRect:Rectangle = bitmap.getColorBoundsRect(maskColor, color, false);
if (colorBoundsRect.width == 0 && colorBoundsRect.height == 0){
trace("empty"); // rect contains no visible pixels
}

Assuming the places where it's not filled are transparent, a simple hitTestPoint should do the trick:
myObj.hitTestPoint( 400.0, 400.0, true ); // true means we use the pixels of the shape and not the bounding box
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestPoint()

Related

Merge two images and retain its transparency

It was a while since I programmed AS3. Now I have a problem where I need to merge the two images where the upper image is a png that must retain its transparency. The upper image is an area that must pass through the lower image. A bit like a masked layer.
The result of this merge should result in a a display object. This object will later be sent to a method with the following signature:
public function addImage (
display_object:DisplayObject,
x:Number = 0,
y:Number = 0,
width:Number = 0,
height:Number = 0,
image_format:String = "PNG",
quality:Number = 100,
alpha:Number = 1,
resizeMode:String = "None",
blendMode:String = "Normal",
keep_transformation:Boolean = true,
link:String = ''
):void
Any advice is of the utmost interest. Thanks!
UPDATE;
After some struggling I've come up with this:
var bitmapDataBuffer:BitmapData = new BitmapData ( front.loader.width, front.loader.height, true );
bitmapDataBuffer.draw ( front.loader );
var bitmapOverlay:BitmapData = new BitmapData ( front.loader.width, front.loader.height, true );
bitmapOverlay.draw ( frontBanner.loader );
var rect:Rectangle = new Rectangle(0, 0, front.loader.width, front.loader.height);
var pt:Point = new Point(0, 0);
var mult:uint = 0x00;
bitmapOverlay.merge(bitmapDataBuffer, rect, pt, mult, mult, mult, mult);
var bmp:Bitmap = new Bitmap(bitmapOverlay);
pdf.addImage(bmp,0,0,0,0,ImageFormat.PNG,100,1,ResizeMode.FIT_TO_PAGE);
The problem is that my background image (represented by bitmapDataBuffer) will be totally overwritten by my upper image (the one I call overlay).
The overlay image is a png image. This image has a part of it that is transparent. Through this transparency I want to see my background image.
Any more suggestions?
You should be more specific about what kind of merge you want. You have a few options:
BitmapData.copyPixels - Provides a fast routine to perform pixel manipulation between images with no stretching, rotation, or color effects. This method copies a rectangular area of a source image to a rectangular area of the same size at the destination point of the destination BitmapData object.
BitmapData.merge - Performs per-channel blending from a source image to a destination image. For each channel and each pixel, a new value is computed based on the channel values of the source and destination pixels.
BitmapData.draw - Draws the source display object onto the bitmap image, using the Flash runtime vector renderer. You can specify matrix, colorTransform, blendMode, and a destination clipRect parameter to control how the rendering performs.
Each will work out for a different thing - the first will just copy some image over another (can keep/merge alphas). The second will merge channels data and modify them. The third one is the easiest and can draw one bitmap over another, as well as use blend modes.
Just chose one! :)
In order to make overlay image over the buffer image in your case, you are to use copyPixels() with mergeAlpha set to true.
bitmapDataBuffer.copyPixels(bitmapOverlay, rect, new Point(), null, null, true);
This will place data from bitmapOverlay to those parts of bitmapDataBuffer where overlay's alpha is above 0, blending semitransparent regions with the background.

as3 - setting textures alpha-value

For an Actionscript 3 "drawing application", I want to be able to chose a Texture and set it's transparency.
Therefore I try to set the alpha-transparency of a texture.
But it's not working.
What I do:
At first I use graphics.linestyle() to set the lines thickness and ALPHA-value.
After that I (a) load a png, (b) read it's bitmapData and (c) then use it with lineBitmapStyle.
Result:
When drawing lines (with moveTo, lineTo, etc) the lines use the texture, but IGNORE THE "Alpha" which was set with lineStyle.
What am I doing wrong?
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, setTexture);
setTexture(e:Event):void
{
e.currentTarget.removeEventListener(e.type, arguments.callee);
//Try 1: Trying to set the Alpha-Trasparency with "lineStyle"-Command:
myDrawContainer.graphics.lineBitmapStyle(5, 0xFF0000, 0,6);
//Try 2: Trying to set the Alpha-Transparency by changing the Alpha-Value of the loaded content:
myLoader.content.alpha = 0.6;
//Getting the BitmapData of the Image:
BitmapDataOfMyTexture = Bitmap(LoaderInfo(e.target).content).bitmapData
//"Using" the TBitmapData as "Color/Texture" for my Drawing:
myDrawContainer.graphics.lineBitmapStyle( BitmapDataOfMyTexture );
//Test-Drawing:
myDrawContainer.graphics.moveTo( 0, 0 );
myDrawContainer.graphics.moveTo( 500, 500 ); //-> RESULT: Textured Line WITHOUT Transparency!
}
RESULT: I get a line which uses the texture but WITHOUT Transparency.
(Update) THE SOLUTION: (Thanks to DodgerThud)
For setting/changing the Alpha-Channel of a loaded image, you don't use "lineStyle" but...
Create a NEW colorTransform-object
Then set it's "alphaMultiplier"-attribute to the specific alphaChannel
And then apply this newly created colorTransform-Object to the loaded BitmapData, by using the "colorTransform"-Method of the loaded BitmapData.
BUT :
This does NOT work with images that don't have an alpha-Channel or don't have their alpha-channel activated. Those images only get DARKER when lowering the alpha-Channel. In those cases you have to do this:
At FIRST I create NEW BitmapData-Object with "new", set its width and height to the width and height of the loaded Image and set it 3rd Argument to TRUE (= transparency: ON). So you got a "Container" which has transparency ACTIVATED.
Then you use "copyPixels" on this "Container"-Object to fill it with the pixels of the LOADED BitmapData-Object.
And right after this the above approach with the "colorTransform"-Object brings the expected result.
So HERE'S THE WORKING CODE:
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, setTexture);
setTexture(e:Event):void
{
e.currentTarget.removeEventListener(e.type, arguments.callee);
//Getting the BitmapData of the Image:
BitmapDataOfMyTexture = Bitmap(LoaderInfo(e.target).content).bitmapData
//Create an ADDITIONAL BitmapData-Object with 3rd
//argument set to TRUE and with same width and height
//as the LOADED image:
var BMDContainerWithAlphaActivated:BitmapData;
BMDContainerWithAlphaActivated = new BitmapData(BitmapDataOfMyTexture.width, BitmapDataOfMyTexture.height, true, 0xFFFFFF);
//Copy the pixels of the loaded image into the newly created
//"BitmapData-Container with activated AlphaChannel":
BMDContainerWithAlphaActivated.copyPixels(BitmapDataOfMyTexture, new Rectangle(0, 0, BitmapDataOfMyTexture.width, BitmapDataOfMyTexture.height), new Point(0,0))
//Modify the Alpha-Value (of the NEW BitmapData-Object):
var colorChanges:ColorTransform = new ColorTransform();
colorChanges.alphaMultiplier = 0.3;
BMDContainerWithAlphaActivated.colorTransform(new Rectangle(0, 0, BitmapDataOfMyTexture.width, BitmapDataOfMyTexture.height), colorChanges);
//"Using" the (NEW) BitmapData as "Color/Texture" for my Drawing:
myDrawContainer.graphics.lineBitmapStyle( BMDContainerWithAlphaActivated );
//Test-Drawing:
myDrawContainer.graphics.moveTo( 0, 0 );
myDrawContainer.graphics.moveTo( 500, 500 ); //-> RESULT: Textured Line WITH Transparency 0.3!
}
Ah I see, this is a bit more complex than I initially thought.
Alright, looking at the documentation for lineBitmapStyle shows me that the function expects the following parameters: lineBitmapStyle(bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false)
Now, matrix, repeat and smooth will not help us here (matrix is used here for transformation, i.e. positioning, rotation etc.), but bitmap:BitmapData might. What we need to do is manipulate the BitmapData of the loaded PNG file before passing it to lineBitmapStyle. Sadly we cannot set the alpha value directly on the BMD, so we can try to colorTransform it.
This is untested code, but I think it is the right approach:
..
//store the bitmapdata in a seperate local variable
var bmd:BitmapData = LoaderInfo(e.target).content;
//create a ColorTransform Object to change the values of the BMD
var cTransform:ColorTransform = new ColorTransform();
//now here I am unsure, manipulating the alpha value of the BMD
cTransform.alphaMultiplier = 0.6;
//defining the rectangle dimensions of the bmd, we want it to be over the entire texture
var rect:Rectangle = new Rectangle(0,0,bmd.width,bmd.height);
//apply the colorTransformation on the BMD
bmd.colorTransform(rect,cTransform);
...
//the now manipulated BMD gets set as lineBitmapStyle
myDrawContainer.graphics.lineBitmapStyle(bmd);
And now that I think about it, maybe we can workaround setting the alpha value on the BMD, by creating a Bitmap first, set the alpha value there and use the bitmapdata of the Bitmap instead. Like this:
var bmd:BitmapData = LoaderInfo(e.target).content;
var bm:Bitmap = new Bitmap(bmd);
bm.alpha = 0.6;
myDrawContainer.graphics.lineBitmapStyle(bm.bitmapData);
Alright, the first snippet from above seems to be the way to do it, but the transparent value of the BitmapData needs to be true. Given that you do not directly create the BitmapData yourself and the value is false, we have quite a tricky situation here.
Another approach would be to create an additional bitmapdata that allows for transparancy and draw() the bitmapdata of the loaded image on it:
var bmdSource:BitmapData = LoaderInfo(e.target).content;
var bmd:BitmapData = new BitmapData(bmdSource.width, bmdSource.height,true,0xffffffff);
var cTransform:ColorTransform = new ColorTransform();
cTransform.alphaMultiplier = 0.6;
var rect:Rectangle = new Rectangle(0,0,bmd.width,bmd.height);
bmd.colorTransform(rect,cTransform);
//now we have a completely white bitmapdata bmd, with an alpha value of 0.6
//we draw the contents of the bmdSource onto bmd, the alpha value effect should carry over
bmd.draw(bmdSource);

AS3 Having trouble understanding Rectangle Intersection

I'm trying to get Rectangle.intersection to provide me with the rectangle of the intersection area of 2 overlapping shapes but not having much success.
The code below is simply 2 shapes the same size. The top most shape is draggable.
When the drag is stopped I perform a bottomRect.intersection(topRect) call but this always returns the full size of the rect, not the intersection size.
(the code can be copied and pasted into a new ActionScript file on the first frame and run.)
Does anyone have an idea where I'm going wrong?
Thanks
import flash.geom.Rectangle;
import flash.display.Sprite;
var bottomSprite:Sprite = new Sprite();
addChild(bottomSprite);
var bottomRect:Shape = new Shape;
bottomRect.graphics.beginFill(0xFF0000);
bottomRect.graphics.drawRect(0, 0, 320,480);
bottomRect.graphics.endFill();
bottomSprite.addChild(bottomRect);
var topSprite:Sprite = new Sprite();
addChild(topSprite);
var topRect:Shape = new Shape;
topRect.graphics.beginFill(0x000033);
topRect.graphics.drawRect(0, 0, 320,480);
topRect.graphics.endFill();
topSprite.addChild(topRect);
var bottomBoundsRect:Rectangle = stage.getBounds(bottomSprite);
trace("START: bottomBoundsRect ", bottomBoundsRect);
var topBoundsRect:Rectangle = stage.getBounds(topSprite);
trace("START: topBoundsRect ", topBoundsRect);
topSprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
topSprite.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
function mouseDownHandler(evt:MouseEvent):void{
topSprite.startDrag();
}
function mouseUpHandler(evt:MouseEvent):void{
topSprite.stopDrag();
topBoundsRect = stage.getBounds(topSprite);
trace("INTERSECTION RECT", bottomBoundsRect.intersection(topBoundsRect));
}
The problem is because of wrong toIntersect property that you pass:
topBoundsRect = stage.getBounds(topSprite);
trace("INTERSECTION RECT", bottomBoundsRect.intersection(topBoundsRect));
What you do is that you get the bounds of the topSprite agains the Stage. If you trace it, it will give you something like this:
(x=-62, y=-41, w=382, h=521)
So you have a bounds that start at 0,0 and have bigger width/height, because you move the topSprite - here I've moved it 62 pixels to the right (382 - 320 [width]), and 41 pixels down (521 - 480 [height]).
The actual intersection of this rectangle against the bottom one, is exactly the size of the bottom one.
What you should do is something similar to this:
// somehow get the rectangle of the bottom sprite
var br:Rectangle = new Rectangle(bottomSprite.x, bottomSprite.y, bottomSprite.width, bottomSprite.height);
// somehow get the rectangle of the top sprite
var tr:Rectangle = new Rectangle(topSprite.x, topSprite.y, topSprite.width, topSprite.height);
trace (br.intersection(tr)); // intersect them
There are few ways to get the bounds, but this is also working and shows the idea.
Hope that helps! :)

AS3: BitmapData linked to certain sprite in library?

I have a problem. I have a sprite added to library and I linked and named its class "CarriedHead_Normal". Now I want to display this sprite and make every black(000000) pixel invisible (just convert background to alpha).
I know I can use this
var bmpd:BitmapData = new BitmapData(width, height, true, 0x000000)
But how am I supposed to merge this with my function, so I call the class from the library and make it's bg transparent?
My current code:
var imageSprite = new Sprite();
addChild(imageSprite);
var libraryImage:Bitmap = new Bitmap(new CarriedHead_Normal(0, 0))
imageSprite.addChild(libraryImage);
Thanks in advance.
A number of ways you could do it, some working better than others:
On a side node, your question title has nothing to do with your actual question
1) Use blend modes
Depending on your graphics and background, you might be able to get away with a simple blendMode - check out BlendMode.SCREEN in particular. Note that some blend modes require that your parent container have a blendMode of BlendMode.LAYER
2) copyPixels() using an alpha BMD
copyPixels() lets you specify an alpha BitmapData to use when deciding which pixels to copy over (actually the alpha value of the pixels to copy over). If you have an alpha BitmapData that matches your black areas, you can remove it like that:
var b:BitmapData = new BitmapData( myImageBMD.width, myImageBMD.height, true, 0x00000000 );
b.copyPixels( myImageBMD, myImageBMD.rect, new Point, alphaBMD, new Point, false ); // copy our image, using alphaBMD to remove the black
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#copyPixels()
3) floodFill() the black areas
If your black area is continuous and you know a pixel that it starts on (e.g. it's a black frame around an image), then you can use floodFill() to remove the black areas
var b:BitmapData = new BitmapData( myImageBMD.width, myImageBMD.height, true, 0x00000000 );
b.copyPixels( myImageBMD, myImageBMD.rect, new Point ); // copy our image so we keep the original
b.floodFill( 0, 0, 0x00000000 ); // assuming the first pixel is black, floodFill() from here, replacing with transparence
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#floodFill()
This technique will work best on pixel art, where the edges are well defined.
4) threshold() to remove the black
threshold() takes pixel values and replaces them with the value you set if they pass a certain test (<, <=, ==, etc). You can use this to replace black with transparence.
var b:BitmapData = new BitmapData( myImageBMD.width, myImageBMD.height, true, 0x00000000 );
b.copyPixels( myImageBMD, myImageBMD.rect, new Point ); // copy our image so we keep the original
b.threshold( b, b.rect, new Point, "==", 0xff000000, 0x00000000 ); // test the pixels; if they're black, replace with transparence
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#threshold()
Again, this works best when the edges are well defined.
5) Use filters
You can use applyFilter() to create a new image, using a BitmapFilter to remove the black. Possibly only of the other filters will work, but ShaderFilter should definitely do the job (you write your own shader, so you can essentially do what you want). I don't have any real experience with filters, so I can't tell you how they work, but some googling should give you the necessary code
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#applyFilter()
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/filters/ShaderFilter.html
6) Use photoshop (or equivalent)
The easiest method; just edit your image to remove the black; much less hassle :)
Try something like:
var libraryImage:Bitmap = spriteToBitmap(new CarriedHead_Normal());
imageSprite.addChild(libraryImage);
function spriteToBitmap(sprite:Sprite, smoothing:Boolean = false):Bitmap
{
var bitmapData:BitmapData = new BitmapData(sprite.width, sprite.height, true, 0x00000000);
bitmapData.draw(sprite);
bitmapData.threshold(bitmapData, bitmapData.rect, new Point(), '==', 0xff000000, 0x00000000);
return new Bitmap(bitmapData, "auto", smoothing);
}

operations with BitmapData

we have a square movie clip with some clild movie clips on it. Consider a diagonal of a squere. I want to make the following transformation with bimap data of a movie clip: the triangle located upper then diagonal should remain unchanged, the lower triangle should be replaced with simetric reflection of upper triangle.
Is there a simple way to do that?
Exactly, the way is to take a snapshot of the movie, then mirror it, take another snapshot and combine these two snapshots.
Note, that the content you will get will be "static", so this way you can't copy the movieclip's animated parts.
//store the movie's graphical content in a bitmapdata
var bmd:BitmapData = new BitmapData(movie.width, movie.height);
bmd.draw(movie);
//then create a temporary movie in which you will do the mirroring
var temp:MovieClip = new MovieClip();
temp.addChild(new Bitmap(bmd));
//create the diagonal mask
var _mask:MovieClip = new MovieClip();
with(_mask.graphics) beginFill(0xff0000), lineTo(movie.width, 0), lineTo(movie.width, movie.height), lineTo(0, 0), endFill();
temp.addChild(_mask);
temp.mask = _mask;
//this is the mirroring part
temp.scaleX = temp.scaleY = -1;
addChild(temp);
//then create another bitmapdata for storing the so called "upper-triangle"
//important, that this bitmapdata should be transparent, "true" sets this
var bmd1:BitmapData = new BitmapData(temp.width, temp.height, true, 0x00);
//then do another mirroring transformation
var matrix:Matrix = new Matrix(-1, 0, 0, -1);
matrix.tx = temp.width;
matrix.ty = temp.height;
//draw the visual content on the bitmapdata
bmd1.draw(temp, matrix);
//and finally, on the original bitmapdata, draw the mirrored part
bmd.draw(bmd1);
//and add it to the top layer of the original movie, or whatever you want to do with it
movie.addChild(new Bitmap(bmd));
The simplest way I can think of is rotating the movieclip 45º and draw the upper rectangle into the lower rectangle inversed, and then rotate the bitmapdata back 45º. You can use a Matrix (2nd argument in the BitmapData.draw method) to draw it rotated and not actually rotate anything.