【问题标题】:AS3 How to check if BitmapData is emptyAS3 如何检查 BitmapData 是否为空
【发布时间】:2011-11-09 02:17:56
【问题描述】:

我有一个代码可以删除蒙版的影片剪辑。 (学分here) 我想知道如何检查整个影片剪辑是否已被删除。 所以我想我必须检查 BitmapData 是否为空,但我可能大错特错! 如何检查影片剪辑的每个像素是否都已被擦除?
当然我下面的例子是错误的,但我认为它必须是这样的。

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);
            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);
    }

【问题讨论】:

    标签: flash actionscript-3 bitmapdata erase


    【解决方案1】:

    您可以检查getColorBoundsRect 是否为您认为“空”的颜色返回一个宽度和高度为0 的矩形,将findColor 参数设置为false。还有其他方法可以做到这一点,但这至少比检查每个像素快很多倍。

    findColor 参数的默认值 true 为您提供了一个矩形,该矩形包围了 (pixelColor & mask) == emptyColor 为 true 的所有像素。在处理 alpha 值时,0xFF000000 的掩码可用于忽略像素的 rbg 值并仅检查其 alpha 值。所以掩码0xFF000000 和颜色0xFF000000 将匹配所有完全不透明的像素,而掩码0xFF000000 和颜色0x00000000 将匹配所有完全透明的像素。正如meddlingwithfire 指出的那样,这在这里不起作用。通过将findColor 设置为false,此过程有点颠倒,因此矩形将使用空颜色包围所有非的像素。对于不包含其他颜色的位图,结果将是一个面积为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
    }
    

    从技术上讲,黑色透明像素 0x00000000 和红色透明像素 0x00FF0000 之间存在差异 - 但没有明显差异(两者都是不可见的),因此您应该像我一样完全忽略 rgb 值在示例中使用该特定掩码。

    【讨论】:

    • 非常感谢您的回答,我尝试了很多东西,这是在正确的方向吗? ------------------------------------- var colorBoundsRect:Rectangle = erasableBitmapData.getColorBoundsRect(0x00FFFFFF, 0x00FF0000,真的); if (colorBoundsRect.? = 0){ trace("empty");}
    • 谢谢,您的解释非常通俗易懂。我收到 1152 错误,因为; 'var 掩码。这可能是因为我已经在这行代码中使用了“掩码”吗? maskee.mask = 可擦除位图; ?
    • @Opoe 不,同名的属性很好。该错误表明继承存在一些问题。或者,也许您在舞台上有一个名为“面具”的对象。这是一个非常奇怪的错误,发生在一个简单的变量声明上。
    • 掩码被认为是保留的所以我把它改成了掩码1。我不再收到错误,但它还没有追踪任何东西。我会尝试更多,还在学习中!
    • 我一直在用这段代码尝试几件事,因为我无法让它工作。我认为是因为它将擦除的线条绘制到精灵上。 'var EraserClip' 部分。会不会跟这个有关系?
    【解决方案2】:

    创建一个基线“空”BitmapData 实例。使用该 BitmapData 的比较方法,传入您的“可能为空”的 BitmapData。您将获得一个新的 BitmapData 引用,其中包含两者之间的像素差异。使用新的 BitmapData 引用,您可以访问 histogram 方法以获取每个通道的所有计数的列表。如果空的 BitmapData 实例和“可能为空”的 BitmapData 实例完全相同,那么您的直方图通道将您的 BitmapData 中的像素总数作为每个通道的零索引中的计数(因为在这种情况下 BitmapData 差异相等的数据将填充 0x00000000 像素)。

    也应该相对较快,因为您可以依靠 AS 引擎查看每个像素,而不必手动调用昂贵的 getPixel() 方法。

    使用颜色边界方法可能会导致误报。如果您的位图在左上角和左下角位置相同,那么您的颜色边界矩形将包含整个区域,即使其间的所有像素可能完全不同。

    【讨论】:

      【解决方案3】:

      BitmapData.compare(BitmapData) 函数返回一个新的BitmapData,其中包含调用两个BitmapDatas 之间的差异,或者如果BitmapData 对象是等效的(具有相同的宽度、高度和相同的像素值) ,该方法返回数字 0。这意味着您可以使用以下内容来检查 DisplayObject 是否包含图形

      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

      【讨论】:

      • 谢谢你,克里斯!我会尽快尝试这个答案,让你知道它是怎么回事:)
      • 没用,我想是因为我使用蒙版来“重新定位”已擦除的像素,你怎么看?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-20
      • 2017-11-15
      • 2020-05-29
      • 2018-04-02
      • 2016-04-05
      • 2018-01-08
      • 2020-09-25
      相关资源
      最近更新 更多