AS3 How to check if BitmapData is empty
I have a code to erase a masked movieclip. (credits here) I would like to know how I can check if the whole movieclip is been erased. So I thought I had to check if the BitmapData is empty, but I could be terribly wrong! How can I check if every pixel of the movieclip has been erased?
Of course my example below is wrong, but I think it has to be something like that.if (erasableBitmapData = empty)
{
trace("empty")
}
var lineSize:Number=40;
var doDraw:Boolean=false;
var resumeDrawing:Boolean=false;
var erasableBitmapData:BitmapData = new BitmapData(700, 500, true, 0xFFFFFFFF);
var erasableBitmap:Bitmap = new Bitmap(erasableBitmapData);
erasableBitmap.cacheAsBitmap = true;
addChild(erasableBitmap);
maskee.cacheAsBitmap = true;
maskee.mask = erasableBitmap;
var eraserClip:Sprite = new Sprite();
initEraser();
function initEraser():void {
eraserClip.graphics.lineStyle(lineSize,0xff0000);
eraserClip.graphics.moveTo(stage.mouseX,stage.mouseY);
}
var drawnBitmapData:BitmapData = new BitmapData(700, 500, true, 0x00000000);
var drawnBitmap:Bitmap = new Bitmap(drawnBitmapData);
stage.addEventListener(MouseEvent.MOUSE_MOVE,maskMove);
stage.addEventListener(MouseEvent.ROLL_OUT, maskOut);
stage.addEventListener(MouseEvent.ROLL_OVER,maskOver);
stage.addEventListener(MouseEvent.MOUSE_DOWN,startDrawing);
stage.addEventListener(MouseEvent.MOUSE_UP,stopDrawing);
function startDrawing(e:MouseEvent):void {
eraserClip.graphics.moveTo(stage.mouseX,stage.mouseY);
doDraw=true;
}
function stopDrawing(e:MouseEvent):void {
doDraw=false;
resumeDrawing = false;
}
function maskOut(e:Event):void {
if (doDraw){
resumeDrawing = true;
}
}
function maskOver(e:MouseEvent):void {
if (resumeDrawing){
resumeDrawing = false;
eraserClip.graphics.moveTo(stage.mouseX,stage.mouseY);
}
}
function maskMove(e:MouseEvent):void {
if (doDraw && !resumeDrawing){
eraserClip.graphics.lineTo(stage.mouseX,stage.mouseY);
drawnBitmapData.fillRect(drawnBitmapData.rect, 0x00000000);
drawnBitmapData.draw(eraserClip , new Matrix(), null, BlendMode.NORMAL);
开发者_如何学Go erasableBitmapData.fillRect(erasableBitmapData.rect, 0xFFFFFFFF);
erasableBitmapData.draw(drawnBitmap, new Matrix(), null, BlendMode.ERASE);
}
e.updateAfterEvent();
}
reset_btn.addEventListener(MouseEvent.CLICK,reset);
function reset(e:Event):void {
eraserClip.graphics.clear();
initEraser();
erasableBitmapData.fillRect(erasableBitmapData.rect, 0xFFFFFFFF);
}
You can check if getColorBoundsRect
returns an rectangle with an width and height of 0
for the colour you consider as 'empty', setting the findColor
argument to false. There are other ways to do this, but this is at least many times faster than checking every single pixel.
The default value of true for the findColor
argument gives you an rectangle that encloses all pixels for those (pixelColor & mask) == emptyColor
is true. When dealing with alpha values, a mask of 0xFF000000
can be used to ignore rbg values of a pixel and to only check its alpha value. So the mask 0xFF000000
and the colour 0xFF000000
would match all fully opaque pixels, while the mask 0xFF000000
and the colour 0x00000000
would match all fully transparent pixels. As meddlingwithfire pointed out, this won't do the job here. By setting findColor
to false, this process is kind of reversed so that the rectangle will enclose all pixels that are not using the empty colour. For bitmaps containing no other colours, the result will be a rectangle with an area of 0
.
var maskColor:uint = 0xFF000000;
var emptyColor:uint = 0x00000000;
var bounds:Rectangle = erasableBitmapData.getColorBoundsRect(maskColor, emptyColor, false);
if (bounds.width == 0 && bounds.height == 0){
trace("empty"); // no visible pixels
}
Technically there is a difference between a black transparent pixel 0x00000000
and for example a red transparent pixel 0x00FF0000
- but there is no visible difference (both are invisible) so you should ignore the rgb values completely, as I did in the example by using that particular mask.
Create a baseline "empty" BitmapData instance. Use that BitmapData's compare method, passing in your "potentially empty" BitmapData. You'll get a new BitmapData reference that has the pixel differences between the two. Using that new BitmapData reference, you can access the histogram method to get a list of all the counts for every channel. If the empty BitmapData instance and the "potentially empty" BitmapData instance are exactly the same, then your histogram channel will have the total number of pixels in your BitmapData as the count in the zero index of each channel (since the BitmapData difference in the case of equal data would be filled with 0x00000000 pixels).
Should be relatively quick too, as you can rely on the AS engine to look at each pixel as opposed to having to manually call the expensive getPixel() method.
Using the color bounds approach can lead to false-positives. If your bitmaps are the same in the upper-left and lower-left positions then your color bounds rect will encompass the entire area, even though all of the pixels in-between could be completely different.
The BitmapData.compare(BitmapData)
function returns either a new BitmapData
containing the difference between the the calling two BitmapData
s, or if the BitmapData
objects are equivalent (with the same width, height, and identical pixel values), the method returns the number 0. Meaning you could use the following to check if a DisplayObject
contains graphics
var eraseableBitmapData:BitmapData = new BitmapData(264,864,true,0xFFFFFFFF);
//initialise the eraseableBitmapData
eraseableBitmapData.draw(someDisplayOject)
//draw your object's bitmap data
var emptyBitmapData:BitmapData = new BitmapData(264,864,true,0xFFFFFFFF);
//create an identical but empty BitmapData object
if( erasableBitmapData.compare ( emptyBitmapData ) == 0 ) {
trace("empty");//object is completely empty
} else {
trace("not empty");//object still has stuff in
}
draw() documentation
compare() documentation
精彩评论