Change the color balance of a Drawable - android

It is possible to change the color balance of a Drawable ?
For example, I would like to convert
to =>
I try this but it change all the colors of my Drawable to one unique color :
Drawable drawable; // my drawable
float r = Color.red(110) / 255f;
float g = Color.green(150) / 255f;
float b = Color.blue(200) / 255f;
ColorMatrix cm = new ColorMatrix(new float[] {
// Change red channel
r, 0, 0, 0, 0,
// Change green channel
0, g, 0, 0, 0,
// Change blue channel
0, 0, b, 0, 0,
// Keep alpha channel
0, 0, 0, 1, 0,
});
ColorMatrixColorFilter cf = new ColorMatrixColorFilter(cm);
drawable.setColorFilter(cf);
I specify I don't want to split my src image into 2 or more layers and colorify one of them.

You can apply a tint with the desired color to your image using mutate().setColorFilter(), and set the Drawable with the new color into your ImageView:
ImageView imgImagen = (ImageView)findViewById(R.id.myImageView);
Drawable myImage = getResources().getDrawable( R.drawable.boy );
//Using red color.
myImage.mutate().setColorFilter(0xffff0000, PorterDuff.Mode.MULTIPLY);
imgImagen.setImageDrawable(myImage);
For example using this ImageView,
<ImageView
android:id="#+id/myImageView"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/boy"
android:contentDescription="" />
you will have this image as result:
You can use too the color defined in your example:
myImage.mutate().setColorFilter(Color.argb(255, 110, 150, 200), PorterDuff.Mode.MULTIPLY);

I can see that your character have eyes and some attribute which need to be safe during color change, so we need more control on that resource therefore we will convert it to bitmap:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.brown_man);
Your bitmap might be not mutable so in order to make it mutable:
Bitmap myBitmap = bitmap.copy(Bitmap.Config.RGB_565, true);
Then we have to getPixels() And re setPixels() with specified color:
int[] pixels = new int[myBitmap.getHeight() * myBitmap.getWidth()];
myBitmap.getPixels(pixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] == color /*Color to change int value*/)
pixels[i] = newColor /*The new color you want to change*/;
}
myBitmap.setPixels(pixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
Thus, you can use this bitmap as you wish.
Some things to take considering:
Your resource character must have a height resolution color to make it easy to specify and change.

Related

Converting color bitmap to grayscale image using only the blue channel using a colormatrix

I need to grayscale a bitmap in Android using only the blue color channel.
I managed to get rid of the green and red channels by using a colormatrix, but when I set the saturation of that matrix to 0 it is ignoring the previously made changes to the red and green channels.
Is there a way to accomplish my task? Iterating through the whole pixel array is not an option as it is way too slow.
I'm using this piece of code:
public Bitmap ConvertToGrayscale(Bitmap bitmap) {
int height = super.getHeight();
int width = super.getWidth();
float[] arrayForColorMatrix = new float[] {0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0};
Bitmap.Config config = bitmap.getConfig();
Bitmap grayScaleBitmap = Bitmap.createBitmap(width, height, config);
Canvas c = new Canvas(grayScaleBitmap);
Paint paint = new Paint();
ColorMatrix matrix = new ColorMatrix(arrayForColorMatrix);
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
paint.setColorFilter(filter);
c.drawBitmap(bitmap, 0, 0, paint);
return grayScaleBitmap;
}
The correct matrix for getting a gray scaled image from the blue channel is the following:
float[] arrayForColorMatrix = new float[] {0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0};
From the Android documentation:
When applied to a color [r, g, b, a], the resulting color is computed as (after clamping):
R' = a*R + b*G + c*B + d*A + e;
G' = f*R + g*G + h*B + i*A + j;
B' = k*R + l*G + m*B + n*A + o;
A' = p*R + q*G + r*B + s*A + t;
Using my arrayForColorMatrix I get the blue value for every value of the RGB color components, which results in a gray scaled bitmap based on the blue channel.

Custom brush stroke android: Black color border around custom shape

I am trying to make a custom brush. I took an image and trying it draw it on canvas when i touch and move the finger. I have a star shape png image with only white color. I planned to change the color according to color selection by user. To change the color I am using color matrix as follows :
float[] colorTransform = { //For red color as of now
1f,0 , 0, 0,0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 1, 0};
ColorMatrix colorMatrix = new ColorMatrix();
// colorMatrix.setSaturation(0f); //Remove Colour
colorMatrix.set(colorTransform); //Apply the Red
ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
Paint paint = new Paint();
paint.setColorFilter(colorFilter);
paint.setAntiAlias(true);
for (Point pos: positions)
canvas.drawBitmap(mBitmapBrush, pos.x, pos.y, paint);
Everything seems to work fine with one problem:
"While drawing Bitmap I am getting a thin black color border around my star shape". Am I using colormatrix in wrong way ? Any suggestions?
Thanks in advance.
If you want to use the color matrix to replace the original color of the bitmap, change the right-most column.
float[] colorTransform = {
0, 0, 0, 0, 255, // Set red component of each output pixel to max
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 1, 0}; // Copy over the alpha channel from the input
The last column is an offset term. It is added to the result, no matter how the input looked like. In above example, 255 is added to the red channel.
Note that the top-left 3x4 submatrix is empty. This essentially discards all color information in the input image. The 5th column adds color again: the color that the user picked.

How can I set the alpha of a bitmap pre-setHasAlpha?

I have a Bitmap and I need to set some of its pixels to transparent. Although I'm creating the Bitmap with Config.ARGB_8888, when I call Bitmap.hasAlpha() on it, it returns false. I can't use Bitmap.setHasAlpha() because that was only added in API level 12 whereas my minimum supported API needs to be 9. How can I do this?
Here you go:
Paint paint = new Paint();
paint.setAlpha(100);
canvas.drawBitmap(bitmap, src, dst, paint);
How to change a bitmap's opacity?
Edit:
//Create an array of pixels of the bitmap using Bitmap getPixels function
//Traverse through the pixels array and if that pixel matches your condition to change it to transparent
// Change the color of that pixel to transparent using Color.Transparent
//Finally set them back using Bitmap setPixels function
Example code:
import android.graphics.Color;
int[] pixels = new int[myBitmap.getHeight()*myBitmap.getWidth()];
myBitmap.getPixels(pixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
//traverse through pixel array and if condition is met
pixels[i] = Color.TRANSPARENT;
myBitmap.setPixels(pixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
how to change the color of certain pixels in bitmap android
// Convert red to transparent in a bitmap
public static Bitmap makeAlpha(Bitmap bit) {
int width = bit.getWidth();
int height = bit.getHeight();
Bitmap myBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int [] allpixels = new int [ myBitmap.getHeight()*myBitmap.getWidth()];
bit.getPixels(allpixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(),myBitmap.getHeight());
myBitmap.setPixels(allpixels, 0, width, 0, 0, width, height);
return myBitmap;
}
The above code is equivalent to setHasAlpha. Give it a Bitmap, and it will return a Bitmap where HasAlpha is true, and will therefore be able to have transparency. This works in API level 8. I have not tested it in anything lower.

Efficient Bitmap masking with black and white alpha mask in Android

I wanted to mask a Bitmap with a black and white alpha mask. My mask image is black and white, the BLACK area means TRANSPARENT and WHITE area means OPAQUE.
What I need is:
When I use this mask image to mask any other image, the area of resultant image should TRANSPARENT if the corresponding area of mask image is BLACK. Otherwise the area of resultant image should be OPAQUE.
I have attached the sample images. Please help me with this guys.
Sample Image:
Sample Image for Masking
What I have tried so far:
The following methods work fine. But they are very slow. I needed some solution that is efficient in terrms of speed and memory than these methods.
First Method:
int width = rgbDrawable.getWidth();
int height = rgbDrawable.getHeight();
if (width != alphaDrawable.getWidth() || height != alphaDrawable.getHeight()) {
throw new IllegalStateException("image size mismatch!");
}
Bitmap destBitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
int[] pixels = new int[width];
int[] alpha = new int[width];
for (int y = 0; y < height; y++)
{
rgbDrawable.getPixels(pixels, 0, width, 0, y, width, 1);
alphaDrawable.getPixels(alpha, 0, width, 0, y, width, 1);
for (int x = 0; x < width; x++)
{
// Replace the alpha channel with the r value from the bitmap.
pixels[x] = (pixels[x] & 0x00FFFFFF) | ((alpha[x] << 8) & 0xFF000000);
}
destBitmap.setPixels(pixels, 0, width, 0, y, width, 1);
}
alphaDrawable.recycle();
rgbDrawable.recycle();
return destBitmap;
Second Method
float[] nlf = new float[] {
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
1, 0, 0, 0, 0};
ColorMatrix sRedToAlphaMatrix = new ColorMatrix(nlf);
ColorMatrixColorFilter sRedToAlphaFilter = new ColorMatrixColorFilter(sRedToAlphaMatrix);
// Load RGB data
Bitmap rgb = rgbDrawable;
// Prepare result Bitmap
Bitmap target = Bitmap.createBitmap(rgb.getWidth(), rgb.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(target);
c.setDensity(Bitmap.DENSITY_NONE);
// Draw RGB data on our result bitmap
c.drawBitmap(rgb, 0, 0, null);
// At this point, we don't need rgb data any more: discard!
rgb.recycle();
rgb = null;
// Load Alpha data
Bitmap alpha = alphaDrawable;
// Draw alpha data on our result bitmap
final Paint grayToAlpha = new Paint();
grayToAlpha.setColorFilter(sRedToAlphaFilter);
grayToAlpha.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
c.drawBitmap(alpha, 0, 0, grayToAlpha);
// Don't need alpha data any more: discard!
alpha.recycle();
alpha = null;
return target;

ColorMatrixColorFilter does not affect alpha values less than 255

I have a method that take a Bitmap and a color, and converts all the pixels on the Bitmap to that color, while keeping the original's alpha values. In addition, the method is written so that as the color passed in gets darker, the Bitmap is made more transparent rather than darker. If the color passed in is completely black, then the Bitmap should be made entirely transparent instead of black.
public static Bitmap colorImage(Bitmap img, int red, int green, int blue) {
int max = blue;
if (red >= green && red >= blue)
max = red;
else if (green >= red && green >= blue)
max = green;
double scale = 255.0 / max;
red = (int)(scale * red);
green = (int)(scale * green);
blue = (int)(scale * blue);
Bitmap resultBitmap = img.copy(Bitmap.Config.ARGB_8888, true);
float[] colorTransform = {
0, 0, 0, 0, red,
0, 0, 0, 0, green,
0, 0, 0, 0, blue,
0, 0, 0, (float) (1f / scale), 0};
ColorMatrix colorMatrix = new ColorMatrix(colorTransform);
ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
Paint paint = new Paint();
paint.setColorFilter(colorFilter);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(resultBitmap, 0, 0, paint);
return resultBitmap;
}
There is an issue with making the Bitmap transparent.
If I set the color matrix so that it is as follows,
float[] colorTransform = {
0, 0, 0, 0, red,
0, 0, 0, 0, green,
0, 0, 0, 0, blue,
0, 0, 0, 0, 0};
the entire Bitmap should be made completely transparent. However, this only works correctly if the original Bitmap has no transparency at all. If the Bitmap has only alpha values of 255 for all of its pixels, then the result is completely transparent. However, if the Bitmap has any pixel with an alpha value of less than 255, the final image will not be transparent, but will have the same alpha values as the original.
Can anybody tell why?
Thanks in advance.
Bitmaps by default have black backgrounds. Setting the Bitmap's background to transparent resolves the issue.
This can be done by adding resultBitmap.eraseColor(Color.argb(0, 0, 0, 0)); after resultBitmap is declared, changing canvas.drawBitmap(resultBitmap, 0, 0, paint); to canvas.drawBitmap(img, 0, 0, paint);.

Categories

Resources