Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android bitmap mask color, remove color

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?

like image 838
ZZZ Avatar asked Jun 21 '11 22:06

ZZZ


2 Answers

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
like image 175
user487252 Avatar answered Sep 22 '22 18:09

user487252


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.

like image 22
Leo Accend Avatar answered Sep 20 '22 18:09

Leo Accend