【问题标题】:Android bitmap mask color, remove colorAndroid位图遮罩颜色,去除颜色
【发布时间】:2011-09-19 22:48:49
【问题描述】:

我正在创建位图,接下来我将在其上绘制第二个纯色位图。 现在我想更改第一个位图,所以我在上面绘制的纯色将是透明的。

或者简单地说,我想从位图中删除一种颜色的所有像素。 我已经尝试了每个颜色过滤器,并且 xfermode 没有运气,除了逐个像素地去除颜色之外,还有其他可能吗?

【问题讨论】:

    标签: android bitmap alpha mask


    【解决方案1】:

    user487252's solution 在 API 级别 16(Jelly Bean)之前就像一个魅力,在这之后,AvoidXfermode 似乎根本不起作用。

    在我的特定用例中,我已将 PDF 页面(通过 APV PDFView)渲染到像素数组 int[] 中,并将其传递给 Bitmap.createBitmap( int[], int, int, Bitmap.Config )。此页面包含绘制在白色背景上的线条艺术,我需要在保留抗锯齿的同时移除背景。

    我找不到完全符合我要求的 Porter-Duff 模式,因此我最终对像素进行了屈曲和迭代,并逐个转换它们。结果出人意料地简单且高效:

    int [] pixels = ...;
    
    for( int i = 0; i < pixels.length; i++ ) {
        // Invert the red channel as an alpha bitmask for the desired color.
        pixels[i] = ~( pixels[i] << 8 & 0xFF000000 ) & Color.BLACK;
    }
    
    Bitmap bitmap = Bitmap.createBitmap( pixels, width, height, Bitmap.Config.ARGB_8888 );
    

    这非常适合绘制线条艺术,因为任何颜色都可以用于线条而不会失去抗锯齿。我在这里使用红色通道,但您可以通过移动16 位而不是8 来使用绿色,或者通过移动24 来使用蓝色。

    【讨论】:

    • 我想使用您的代码,但我不知道如何使用自定义颜色。请帮忙
    • 您可以将上面代码中的Color.BLACK替换为不同颜色的线条(例如:Color.RED0xFF3399FF)。
    【解决方案2】:

    这适用于从位图中删除某种颜色。主要部分是AvoidXfermode的使用。如果尝试将一种颜色更改为另一种颜色,它也应该可以工作。

    我应该补充一点,这回答了从位图中删除颜色的问题标题。像OP所说的那样,使用PorterDuff Xfermode可能会更好地解决具体问题。

    // start with a Bitmap bmp
    
    // make a mutable copy and a canvas from this mutable bitmap
    Bitmap mb = bmp.copy(Bitmap.Config.ARGB_8888, true);
    Canvas c = new Canvas(mb);
    
    // get the int for the colour which needs to be removed
    Paint p = new Paint();
    p.setARGB(255, 255, 0, 0); // ARGB for the color, in this case red
    int removeColor = p.getColor(); // store this color's int for later use
    
    // Next, set the alpha of the paint to transparent so the color can be removed.
    // This could also be non-transparent and be used to turn one color into another color            
    p.setAlpha(0);
    
    // then, set the Xfermode of the pain to AvoidXfermode
    // removeColor is the color that will be replaced with the pain't color
    // 0 is the tolerance (in this case, only the color to be removed is targetted)
    // Mode.TARGET means pixels with color the same as removeColor are drawn on
    p.setXfermode(new AvoidXfermode(removeColor, 0, AvoidXfermode.Mode.TARGET));
    
    // draw transparent on the "brown" pixels
    c.drawPaint(p);
    
    // mb should now have transparent pixels where they were red before
    

    【讨论】:

    • 这似乎在 API 级别 16 中不起作用,并且 AvoidXferMode 已被弃用,没有解释。不过,这个解决方案确实可以一直工作到 API 级别 15。
    • @LeoAccend 查看源代码的更改历史记录,它似乎已被弃用,因为它不支持硬件加速。
    【解决方案3】:

    逐像素不是一个糟糕的选择。只是不要在循环中调用 setPixel 。用 getPixels 填充一个 argb int 数组,如果不需要保留原来的就修改它,然后在最后调用 setPixels。如果内存是一个问题,您可以逐行执行此操作,或者您可以一次完成整个操作。您不需要为叠加颜色填充整个位图,因为您只需进行简单替换(如果当前像素为 color1,则设置为 color2)。

    【讨论】:

    • 谢谢,但我终于想出了如何用 porterduff 来做到这一点,xfermode(xor) 做到了,但应用于其他位图,首先我将蒙版和源合并并尝试使用滤色器在画布上绘制它,但最后我发现我应该在源上绘制遮罩时使用 xfermode,而不是画布:)
    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 2013-07-23
    • 2011-05-25
    • 2020-04-27
    • 2014-09-29
    • 1970-01-01
    • 2018-01-06
    • 1970-01-01
    相关资源
    最近更新 更多