49

I am developing an android application in which I set an image to imageview. Now programmatic I want to change the bitmap image color. Suppose my image have red color initially and now I need to change it to orange color. How can I do that? Please help.

Here is my code. I managed to change the opacity but I do not know how to change the color.

  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ImageView iv = (ImageView) findViewById(R.id.img);
        Drawable d = getResources().getDrawable(R.drawable.pic1);
        Bitmap mNewBitmap = ((BitmapDrawable)d).getBitmap();
        Bitmap nNewBitmap = adjustOpacity(mNewBitmap);
        iv.setImageBitmap(nNewBitmap);
    }

    private Bitmap adjustOpacity( Bitmap bitmap ) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Bitmap dest = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        int[] pixels = new int[width * height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
        dest.setPixels(pixels, 0, width, 0, 0, width, height);
        return dest;
    } 
Gopal Singh Sirvi
  • 4,539
  • 5
  • 33
  • 55
  • Hi, I have the same problem as I managed to change the brightness of the image using ColorMatrix but I am not getting any idea about to change image color. Thanks, AndroidVogue –  May 09 '11 at 09:40

10 Answers10

66

I tried Josip's answer but wouldn't work for me, regardless of whether the offset parameter was 1 or 0 - the drawn bitmap just appeared in original colour.

However, this did work:

// You have to copy the bitmap as any bitmaps loaded as drawables are immutable
Bitmap bm = ImageLoader.getInstance().loadImageSync("drawable://" + drawableId, o)
            .copy(Bitmap.Config.ARGB_8888, true);

Paint paint = new Paint();
ColorFilter filter = new PorterDuffColorFilter(ContextCompat.getColor(this, R.color.COLOR_1_DARK), PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);

Canvas canvas = new Canvas(bm);
canvas.drawBitmap(bm, 0, 0, paint);

Update 1

Whilst the above works well and is useful in a lot of cases, if you just want to change the main colour of an ImageView drawable, which the op did, you can just use:

imgView.setColorFilter(ContextCompat.getColor(this, R.color.COLOR_1_DARK));

If you need more flexibility or this doesn't give the desired effect, there's an overload that allows you to change the PorterDuff Mode until you get what you're after:

imgView.setColorFilter(ContextCompat.getColor(this, R.color.COLOR_1_DARK), PorterDuff.Mode.SRC_ATOP);

Update 2

Another good use case I've had for this lately is customizing the appearance of a Google map v2 marker icon. In order to use 2 graphics to allow (for example) small/large icons on a marker, but also a range of colours on those 2 graphics by changing the colour of them dynamically. In my case I was doing this inside a ClusterRenderer as the markers were also clustered, but this can be used with a regular map marker the same way:

@Override
protected void onBeforeClusterItemRendered(MyClusterItem item, MarkerOptions markerOptions) {
    try {
        int markerColor = item.getColor();

        Bitmap icon;

        if (item.isFeatured()) {
            // We must copy the bitmap or we get an exception "Immutable bitmap passed to Canvas constructor"
            icon = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.icon_marker_large).copy(Bitmap.Config.ARGB_8888, true);
        } else {
            // We must copy the bitmap or we get an exception "Immutable bitmap passed to Canvas constructor"
            icon = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.icon_marker_small).copy(Bitmap.Config.ARGB_8888, true);
        }

        Paint paint = new Paint();
        ColorFilter filter = new PorterDuffColorFilter(ContextCompat.getColor(context, markerColor), PorterDuff.Mode.SRC_IN);
        paint.setColorFilter(filter);

        Canvas canvas = new Canvas(icon);
        canvas.drawBitmap(icon, 0, 0, paint);

        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}
Breeno
  • 3,007
  • 2
  • 31
  • 30
  • This worked for me when I colored my image to bright colors, which happened to be exactly what I needed. +1 – Android Sep 09 '15 at 00:29
  • I use this to change the irregular shape background image of my text view, it works fine. – cuble Feb 25 '16 at 01:38
44

I got kind of solution.

    Bitmap sourceBitmap = BitmapFactory.decodeFile(imgPath);
    float[] colorTransform = {
            0, 1f, 0, 0, 0, 
            0, 0, 0f, 0, 0,
            0, 0, 0, 0f, 0, 
            0, 0, 0, 1f, 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);   

    Display display = getWindowManager().getDefaultDisplay(); 

    Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, (int)(display.getHeight() * 0.15), display.getWidth(), (int)(display.getHeight() * 0.75));            

    image.setImageBitmap(resultBitmap);

    Canvas canvas = new Canvas(resultBitmap);
    canvas.drawBitmap(resultBitmap, 0, 0, paint);
32
private void changeColor(){
    ImageView image = (ImageView) findViewById(R.id.imageView1);
    Bitmap sourceBitmap = BitmapFactory.decodeResource(getResources(),
            R.drawable.ic_launcher);
    changeBitmapColor(sourceBitmap, image, Color.BLUE);

}

private void changeBitmapColor(Bitmap sourceBitmap, ImageView image, int color) {

    Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0,
            sourceBitmap.getWidth() - 1, sourceBitmap.getHeight() - 1);
    Paint p = new Paint();
    ColorFilter filter = new LightingColorFilter(color, 1);
    p.setColorFilter(filter);
    image.setImageBitmap(resultBitmap);

    Canvas canvas = new Canvas(resultBitmap);
    canvas.drawBitmap(resultBitmap, 0, 0, p);
}
Josip
  • 1,061
  • 1
  • 9
  • 10
  • i think this should be faster than the way user744881 suggested if you only want to change a color but i'm not quite sure.. – A. Binzxxxxxx Mar 04 '14 at 10:39
  • Why is the 1 value is used as a second parameter in LightingColorFilter(color, 1)? According to stackoverflow.com/a/7049965/1245231 this doesn't make much sense. Both parameters are Android color values encoded in int. The value 1 therefore equals to #00000001 color which is added to all pixels. This only adds a little bit of blue color to all pixels which was not intended. Instead of 1 it makes more sense to use just 0: LightingColorFilter(color, 0). Also If I understand it well this answer works correctly only for white source images. But not at all for black only source images. – petrsyn Mar 13 '14 at 23:58
  • This isn't completely relevant but opengl has some problems with preserving opacity of color 0. So it's good practice to set it to 1. It'd be barely, if at all, visible. – soroosh.strife Jan 09 '15 at 17:40
  • 2
    Why is the -1 width and height? – Adam Varhegyi Nov 02 '15 at 13:58
  • @AdamVarhegyi The -1 on width and height is to force the createBitmap function to return a copy. The relevant quote from the documentation: "If the specified width and height are the same as the current width and height of the source bitmap, the source bitmap is returned and no new bitmap is created." I think the only reason the function is being called is in case sourceBitmap is immutable then the Canvas will fail. – Henry Mar 22 '16 at 10:47
13

It's better obtain mutable bitmap by copy, without changing size:

public static Bitmap changeBitmapColor(Bitmap sourceBitmap, int color)
{
    Bitmap resultBitmap = sourceBitmap.copy(sourceBitmap.getConfig(),true);
    Paint paint = new Paint();
    ColorFilter filter = new LightingColorFilter(color, 1);
    paint.setColorFilter(filter);
    Canvas canvas = new Canvas(resultBitmap);
    canvas.drawBitmap(resultBitmap, 0, 0, paint);
    return resultBitmap;
}
Aliaksei Rak
  • 327
  • 3
  • 6
7
public Bitmap replaceColor(Bitmap src,int fromColor, int targetColor) {
    if(src == null) {
        return null;
    }
    // Source image size
    int width = src.getWidth();
    int height = src.getHeight();
    int[] pixels = new int[width * height];
    //get pixels
    src.getPixels(pixels, 0, width, 0, 0, width, height);

    for(int x = 0; x < pixels.length; ++x) {
        pixels[x] = (pixels[x] == fromColor) ? targetColor : pixels[x];
    }
    // create result bitmap output
    Bitmap result = Bitmap.createBitmap(width, height, src.getConfig());
    //set pixels
    result.setPixels(pixels, 0, width, 0, 0, width, height);

    return result;
}
DEVSHK
  • 833
  • 11
  • 10
  • 2
    also check this link https://shaikhhamadali.blogspot.com/2013/08/changereplacementremove-pixel-colors-in.html – DEVSHK Mar 17 '19 at 06:18
  • thanks, also for change color to white,i changed code to this ` pixels[x] = (pixels[x] != Color.TRANSPARENT) ? Color.WHITE : pixels[x];` – abbasalim Dec 25 '19 at 06:29
6

The simplest way to change the bitmaps color is with this method:

bitmap.eraseColor(ContextCompat.getColor(this, R.color.your_color));

If you want to overlay the ImageView with color use:

imageView.setColorFilter(ContextCompat.getColor(this, R.color.your_color));
box
  • 4,450
  • 2
  • 38
  • 38
1

A little off topic, but considering you only want to display in changed color here is my solution. Namely, the easiest and fast way is just applying a filter by using drawColor() method on Canvas, right after drawBitmap():

 m_canvas.drawColor(Color.RED, PorterDuff.Mode.ADD);

Sources: https://developer.android.com/reference/android/graphics/PorterDuff.Mode.html

TomeeNS
  • 455
  • 4
  • 10
1

Even if bitmap is immutable, it will work.

 Paint paint = new Paint();
 ColorFilter filter = new PorterDuffColorFilter(ContextCompat.getColor(context, R.color.whatColorNeed), PorterDuff.Mode.SRC_IN);

 paint.setColorFilter(filter);

 canvas.drawBitmap(bitmapToModify, some_x, some_y, paint);
sapeg
  • 109
  • 7
0

I have solved the problem by using the below code

public void changeColor(Bitmap srcImage) {

    Bitmap bmpRedscale = Bitmap.createBitmap(srcImage.getWidth(), 
    srcImage.getHeight(), Bitmap.Config.ARGB_8888);

    Canvas canvas = new Canvas(bmpRedscale);
    Paint paint = new Paint();

    ColorMatrix cm = new ColorMatrix();
    cm.setRGB2YUV();
    paint.setColorFilter(new ColorMatrixColorFilter(cm));
    canvas.drawBitmap(srcImage, 0, 0, paint);

    mImgEdited.setImageBitmap(bmpRedscale);
}
anemo
  • 1,327
  • 1
  • 14
  • 28
0

In Kotlin :

private fun changeBitmapColor(oldBitmap: Bitmap, newColor: Int): Bitmap {
    val paint = Paint()
    val filter: ColorFilter = PorterDuffColorFilter(
        newColor,
        PorterDuff.Mode.SRC_IN
    )
    paint.colorFilter = filter

    val canvas = Canvas(oldBitmap)
    canvas.drawBitmap(oldBitmap, 0f, 0f, paint)
    return oldBitmap
}

This function PorterDuff.Mode.SRC_IN can change due to the Bitmap file, look this link https://developer.android.com/reference/android/graphics/PorterDuff.Mode enter image description here

Mori
  • 2,653
  • 18
  • 24