I am using a few of the stock Android resources, such as ic_menu_camera.png:
The images have a transparent background (desired), but also some transparency in the coloured pixels, too (undesired).
I'm using a ColorMatrixColorFilter to apply a tint to these images and that's working fine, however, the small amount of transparency in the icons is causing the underlying background to bleed through, and fading the colour. I can't figure out a programmatic way to set all coloured pixels to be opaque. Any help?
Current colouring code:
public static void colorImageView(Context context, ImageView imageView, #ColorRes int colorResId) {
Drawable drawable = imageView.getDrawable();
int color = context.getResources().getColor(colorResId);
drawable.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(new float[] {
0, 0, 0, 0, Color.red(color),
0, 0, 0, 0, Color.green(color),
0, 0, 0, 0, Color.blue(color),
0, 0, 0, 1, 0,
})));
}
Current result:
(first icon's source image is opaque, whereas the other 3 have undesired transparency, leading to this off-blue colour)
A very simple approach came to my mind first:
Maybe you could convert the Drawable into a Bitmap and perform the desired pixel operations (like in this answer), e.g:
for(int x = 0; x < bitmap.getWidth(); x++) {
for(int y = 0; y < bitmap.getHeight(); y++) {
int pixel = bitmap.getPixel(x, y);
int r = Color.red(pixel), g = Color.green(pixel), b = Color.blue(pixel);
if (r != 0 || g != 0 || b != 0)
{
pixel.setPixel(x, y, Color.rgb(r, g, b));
}
}
}
to delete any alpha channel value in each pixel with an r-, g- or b-value higher than zero.
But I dont know, how poor or slow this approach works. I think the conversion into a bitmap with pixel operations might be much slower than a ColorMatrixColorFilter.
Related
I'm trying to convert all the black pixels in one Bitmap (Created from an ImageView that was a PNG file)..
I've tried it in many ways but I still couldn't succeed in that.
Please help me I'm trying it for like 3 days straight...
A little example of my code:
headSkin.buildDrawingCache();
final Bitmap bmp = headSkin.getDrawingCache();
int w = bmp.getWidth();
int h = bmp.getHeight();
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int color = bmp.getPixel(x, y);
// Shift your alpha component value to the red component's.
bmp.setPixel(x, y, Color.RED);
}
}
As you can see... I didn't even state an IF statement..
I just tried to make all the pixels red in this bitmap and even this didn't work.. pls help?
I see 2 problems here,
First, you have this Bitmap object in your memory, and you change the black pixels to red, but how do you know if it is changed or not? You should set an ImageView to this Bitmap to see the result (or save it to file etc.)
Second, use getPixels and setPixels instead, getPixels will give you 1 dimensional array, it goes like 1.row, 2.row, 3.row etc. And setPixels also accepts a 1 dimensional array. This function is incredibly faster than altering pixels 1 by 1.
#Anil
Hi dude, just tried it and I can't use it 'cuz of IndexOutOfBound exception...
headSkin.buildDrawingCache();
bmp = headSkin.getDrawingCache();
int [] allpixels = new int [bmp.getHeight()*bmp.getWidth()];
bmp.getPixels(allpixels, 0, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight());
for(int i = 0; i < allpixels.length; i++)
{
if(allpixels[i] == Color.BLACK)
{
allpixels[i] = Color.RED;
}
}
bmp.setPixels(allpixels, 0, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight());
headSkin.setImageBitmap(bmp);
what is the problem here?
EDIT: Just tried it now while running, not debugging and it doesn't even show me an error or something.. It just makes about 1-2 single pixels red in this whole bitmap
headSkin.buildDrawingCache();
final Bitmap bmp = headSkin.getDrawingCache();
I think you have problem on these lines. The rest of the code looks fine.
Maybe the bitmap is not initialized, so you only have a Bitmap reference, instead of Bitmap object with data inside.
Can you delete the bitmap part from your code and initialize Bitmap like this:
Bitmap myBitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.RGB8888);
and then perform pixel operations like you did above, just set all the pixels to same color.
I'm using c code to get frame from a gif file and it's working fine using ffmpeg library av_read_frame, then I convert the returned image from this format BGRA to ARGB format using this method libyuv::ABGRToARGB.
In the java part I receive the bitmap and when I put it in the ImageView the transparent pixels drawn white.
Bitmap bitmap= Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
getGifFrame(gifFile,bitmap); //native method which get image frame from gif file.
imageTest.setImageBitmap(backgroundBitmap);//this bitmap in debug mode I can see that it has transparent pixels, but in drawn it appears white!
even when I loop on the returned bitmap pixels and check for each pixel I find them transparent!
for (int x = 0; x < b.getWidth(); x++)
{
for (int y = 0; y < b.getHeight(); y++)
{
int color = b.getPixel(x, y);
if (color == Color.WHITE)//This condition never occurred
{
b.setPixel(x, y, Color.TRANSPARENT);
}
}
}
Nothing happened and it's still white. Then I did convert all transparent pixels to TRANSPARENT !! and guess what, It's working!
else if (color == Color.TRANSPARENT)
{
b.setPixel(x, y, Color.TRANSPARENT);
}
I don't understand why that happen. Any help would be appreciated.
EDIT 1:
I get all pixels from the bitmap and set them again without doing anything and it worked also!?
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
bitmap.setPixels(pixels, 0, width, 0, 0, width,height);
I have this piece of code that takes the bitmap of a CameraPreview from a TextureView and renders it on a ImageView.
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Invoked every time there's a new Camera preview frame
bmp = mTextureView.getBitmap();
bmp2 = bmp.copy(bmp.getConfig(),true);
for(int x=0;x<bmp.getWidth();x++){
for(int y=0;y<bmp.getHeight();y++){
//Log.i("Pixel RGB (Int)", Integer.toString(bmp.getPixel(x,y)));
if(bmp.getPixel(x,y) < -8388608){
bmp2.setPixel(x,y,Color.WHITE);
}else{
bmp2.setPixel(x,y,Color.BLACK);
}
}
}
mImageView.setImageBitmap(bmp2);
}
So basically I will be applying real-time image-processing on whatever the camera shows. For now it just back and whites pixels. It is a bit slow now, and the bitmap has only a width and height of ~250 pixels.
Is this the recommended way of doing this ?
To filter bitmaps efficiently you can use ColorMatrixColorFilter. For example to make your image black & white use this code:
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0);
float m = 255f;
float t = -255*1.2f;
ColorMatrix threshold = new ColorMatrix(new float[] {
m, 0, 0, 1, t,
0, m, 0, 1, t,
0, 0, m, 1, t,
0, 0, 0, 1, 0
});
// Convert to grayscale, then scale and clamp
colorMatrix.postConcat(threshold);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
imageView.setColorFilter(filter);
Basically you have to transform the color range so values equal to (color) and (color+1) are (0) and (1). That's why I'm multiplying color by 255 and shifting. You may want to play with these parameters to get the right result.
Check out the slides here: http://chiuki.github.io/android-shaders-filters/#/16
I have images which I display in my app. They are downloaded from the web. These images are pictures of objects on an almost-white background. I want this background to be white (#FFFFFF). I figure, if I look at pixel 0,0 (which should always be off-white), I can get the color value and replace every pixel in the image having that value with white.
This question has been asked before and the answer seems to be this:
int intOldColor = bmpOldBitmap.getPixel(0,0);
Bitmap bmpNewBitmap = Bitmap.createBitmap(bmpOldBitmap.getWidth(), bmpOldBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpNewBitmap);
Paint paint = new Paint();
ColorFilter filter = new LightingColorFilter(intOldColor, Color.WHITE);
paint.setColorFilter(filter);
c.drawBitmap(bmpOriginal, 0, 0, paint);
However, this isn't working.
After running this code, the entire image seems to be the color I was wanting to remove. As in, the entire image is 1 solid color now.
I was also hoping to not have to loop through every pixel in the entire image.
Any ideas?
Here is a method I created for you to replace a specific color for the one you want. Note that all the pixels will get scanned on the Bitmap and only the ones that are equal will be replaced for the one you want.
private Bitmap changeColor(Bitmap src, int colorToReplace, int colorThatWillReplace) {
int width = src.getWidth();
int height = src.getHeight();
int[] pixels = new int[width * height];
// get pixel array from source
src.getPixels(pixels, 0, width, 0, 0, width, height);
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
int A, R, G, B;
int pixel;
// iteration through pixels
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
// get current index in 2D-matrix
int index = y * width + x;
pixel = pixels[index];
if(pixel == colorToReplace){
//change A-RGB individually
A = Color.alpha(colorThatWillReplace);
R = Color.red(colorThatWillReplace);
G = Color.green(colorThatWillReplace);
B = Color.blue(colorThatWillReplace);
pixels[index] = Color.argb(A,R,G,B);
/*or change the whole color
pixels[index] = colorThatWillReplace;*/
}
}
}
bmOut.setPixels(pixels, 0, width, 0, 0, width, height);
return bmOut;
}
I hope that helped :)
I've got a Bitmap with some transparent pixels and rest is mainly black (some black pixels possibly have a few sem-transparent pixels).
I need to re-use these bitmaps and want to be able to essentially create a Mask out of this bitmap at runtime and then try and blend with a block of another color (like Red, green etc) so that the end result is the same image but with red color (and those pixels which were semi-transparent black pixels turn into semi-transparent red pixels).
I've tried all sorts of color filters and xfermodes but have not been able to figure out. Please help!
If you doesn't need high speed, you can use simple solution by manually blend pixels.
final Bitmap bmp = /* there your bitmap */;
int w = bmp.getWidth();
int h = bmp.getHeight();
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int color = bmp.getPixel(x, y);
// Shift your alpha component value to the red component's.
color = (color << 24) & 0xFF000000;
bmp.setPixel(x, y, color);
}
}
If you need more effective processing, you must use (at least) getPixels method or, more preferable, native processing.
public void changeColor(Bitmap myBitmap) {
int [] allpixels = new int [myBitmap.getHeight()*myBitmap.getWidth()];
myBitmap.getPixels(allpixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
for(int i = 0; i < allpixels.length; i++)
{
if(allpixels[i] == Color.BLACK)
{
allpixels[i] = Color.RED;
}
}
myBitmap.setPixels(allpixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
}