Android 位图遮罩颜色、移除颜色

发布于 2024-11-16 10:45:48 字数 144 浏览 3 评论 0原文

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

或者简单地说,我想从位图中删除一种颜色的所有像素。 我尝试了所有滤色器和 xfermode,但没有成功,除了逐像素去除颜色之外,还有其他可能性吗?

I am creating bitmap, next i am drawing second solid color bitmap on top of it.
And now i want to change first bitmap, so solid color that i drawed on it will be transparent.

Or simply, i want to remove all pixels of one color from bitmap.
I havie tried every colorfilter, and xfermode with no luck, is there any other possibility to remove color other that doing it pixel by pixel?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

等往事风中吹 2024-11-23 10:45:48

这适用于从位图中删除某种颜色。主要部分是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

This works for removing a certain color from a bitmap. The main part is the use of AvoidXfermode. It should also work if trying to change one color to another color.

I should add that this answers the question title of removing a color from a bitmap. The specific question is probably better solved using PorterDuff Xfermode like the OP said.

// 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
巨坚强 2024-11-23 10:45:48

user487252 的解决方案在 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 使用蓝色通道。

user487252's solution works like a charm up until API level 16 (Jelly Bean), after which AvoidXfermode does not seem to work at all.

In my particular use case, I have rendered a page of a PDF (via APV PDFView) into a pixel array int[] that I am going to pass into Bitmap.createBitmap( int[], int, int, Bitmap.Config ). This page contains line art drawn onto a white background, and I need to remove the background while preserving the anti-aliasing.

I couldn't find a Porter-Duff mode that did exactly what I wanted, so I ended up buckling and iterating through the pixels and transforming them one by one. The result was surprisingly simple and performant:

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

This is perfect for drawing line art, since any color can be used for the lines without losing the anti-aliasing. I'm using the red channel here, but you can use green by shifting 16 bits instead of 8, or blue by shifting 24.

撩发小公举 2024-11-23 10:45:48

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

Pixel by pixel is not a bad option. Just don't call setPixel inside your loop. Fill an array of argb ints with getPixels, modify it in place if you don't need to preserve the original, and then call setPixels at the end. You can do this row-by-row if memory is a concern, or you can just do the whole thing in one shot. You don't need to fill a whole bitmap for your overlay color since you'd just be doing a simple replace (if current pixel is color1, set to color2).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文