1084

I would like to set a certain Drawable as the device's wallpaper, but all wallpaper functions accept Bitmaps only. I cannot use WallpaperManager because I'm pre 2.1.

Also, my drawables are downloaded from the web and do not reside in R.drawable.

Praveen
  • 90,477
  • 74
  • 177
  • 219
Rob
  • 15,041
  • 6
  • 25
  • 27

22 Answers22

1398

This piece of code helps.

Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
                                           R.drawable.icon_resource);

Here a version where the image gets downloaded.

String name = c.getString(str_url);
URL url_value = new URL(name);
ImageView profile = (ImageView)v.findViewById(R.id.vdo_icon);
if (profile != null) {
    Bitmap mIcon1 =
        BitmapFactory.decodeStream(url_value.openConnection().getInputStream());
    profile.setImageBitmap(mIcon1);
}
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Praveen
  • 90,477
  • 74
  • 177
  • 219
829
public static Bitmap drawableToBitmap (Drawable drawable) {
    Bitmap bitmap = null;

    if (drawable instanceof BitmapDrawable) {
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        if(bitmapDrawable.getBitmap() != null) {
            return bitmapDrawable.getBitmap();
        }
    }

    if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
        bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
    } else {
        bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    }

    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
}
André
  • 12,497
  • 6
  • 42
  • 44
  • 52
    This looks like the only answer that would work for any kind of drawable and also has a quick solution for a drawable that is already a BitmapDrawable. +1 – Matt Wolfe Jun 06 '12 at 22:37
  • Add @Mauro's solution to this after the check for BitmapDrawable and you've got a very ideal solution with any/ all quicker solutions Incorporated. – Tom Jul 04 '12 at 23:45
  • 1
    just one amendment: docs says about BitmapDrawable.getBitmap() that it may come back null. I say it may also come back already recycled. – kellogs Sep 01 '12 at 21:20
  • 17
    Watch out: `getIntrinsicWidth()` and `getIntrinsicHieght()` will return -1 if drawable is a solid color. – S.D. Oct 12 '12 at 13:51
  • 5
    So... another check for ColorDrawable, and we have a winner. Seriously, someone make this the accepted answer. – kaay Jan 14 '13 at 12:41
  • @kaay You can't really make another check for that, as you would still need width/height to create a canvas to draw the ColorDrawable, so you just need to make this method also take width and height as a parameter – nbarraille Jul 28 '14 at 19:08
  • @nbarraille In that case, you could just create a 1x1 pixel bitmap, and you're done. No extra parameters needed. – matiash Jan 23 '15 at 18:14
  • 1
    This doesn't work for all drawable types. For example GradientDrawable which i tried: java.lang.ClassCastException: android.graphics.drawable.GradientDrawable cannot be cast to android.graphics.drawable.BitmapDrawable – Anonymous Mar 21 '15 at 20:36
  • 1
    André you rocks dude! this help me with a RecyclerView that use a same ImageView with DrawableCompat tint. – Vinicius DSL Jul 10 '15 at 15:06
  • `BitmapDrawable` fast path ignores possible tint, color filter, alpha. – Miha_x64 Mar 13 '23 at 05:12
221

This converts a BitmapDrawable to a Bitmap.

Drawable d = ImagesArrayList.get(0);  
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();
varun
  • 768
  • 7
  • 19
Rob
  • 15,041
  • 6
  • 25
  • 27
  • 10
    is this really the best way? Surely the drawable could be of another type and this would throw a runtimeException? For example it could be a ninePatchDrawble...? – Dori Jun 09 '11 at 11:38
  • 4
    @Dori you could wrap the code in a conditional statement to check if it is indeed a `BitmapDrawable` before casting it: `if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }` – Tony Chan Jul 09 '11 at 01:57
  • 396
    Can't believe the 64 upvotes? That code obviously only works if `d` already *is* a `BitmapDrawable`, in which case it's trivial to retrieve it as a bitmap... Will crash with `ClassCastException` in all other cases. – mxk Nov 03 '11 at 16:12
  • 3
    @Matthias not to mention that.. the question itself, same author, has 100 votes :/ – quinestor Dec 18 '12 at 17:29
  • 2
    This is so specialized to a trivial case. – njzk2 May 28 '13 at 11:48
  • 2
    For those who are complaining that this is wrong, have you guys checked the SO about page? It says that accepted answers do not necessarily mean the answer is correct, it means that the answer worked for the OP. – bytehala Apr 07 '14 at 01:33
  • 1
    Too specialized. This does *not* answer the OP's question "How to convert a Drawable to a Bitmap?" it answers "How can I convert a **BitmapDrawable** to a bitmap?" Big difference. – Atorian May 15 '14 at 21:34
  • 1
    @lemuel That does NOT mean we must refrain from pointing out the fact that the answer is WRONG. – RestInPeace May 26 '14 at 02:37
  • I'm sorry if my comment offended you @RestInPeace – bytehala May 29 '14 at 09:01
  • 2
    Surprise is: When a comment gets more up votes than answer itself. – Faizan Mubasher Sep 22 '14 at 12:04
  • After the introduction of `Adaptive` icons with Android Oreo, this started to cause lots of crashes with the apps that display other apps icons. – tasomaniac Dec 29 '17 at 21:04
  • this gives ClassCastException – Silambarasan Nov 25 '19 at 05:53
  • This is totally mistake. How do you confirm that an instance of a Drawable is an instance of BitmapDrawable? Furthermore, who told you that you can force cast an instance of a class to its subclass reference? Especially without a try/catch, you will have a exception in some cases. – Chinese Cat Dec 19 '20 at 06:38
155

A Drawable can be drawn onto a Canvas, and a Canvas can be backed by a Bitmap:

(Updated to handle a quick conversion for BitmapDrawables and to ensure that the Bitmap created has a valid size)

public static Bitmap drawableToBitmap (Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable)drawable).getBitmap();
    }

    int width = drawable.getIntrinsicWidth();
    width = width > 0 ? width : 1;
    int height = drawable.getIntrinsicHeight();
    height = height > 0 ? height : 1;

    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap); 
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}
kabuko
  • 36,028
  • 10
  • 80
  • 93
65

METHOD 1 : Either you can directly convert to bitmap like this

Bitmap myLogo = BitmapFactory.decodeResource(context.getResources(), R.drawable.my_drawable);

METHOD 2 : You can even convert the resource into the drawable and from that you can get bitmap like this

Bitmap myLogo = ((BitmapDrawable)getResources().getDrawable(R.drawable.logo)).getBitmap();

For API > 22 getDrawable method moved to the ResourcesCompat class so for that you do something like this

Bitmap myLogo = ((BitmapDrawable) ResourcesCompat.getDrawable(context.getResources(), R.drawable.logo, null)).getBitmap();
Keyur Lakhani
  • 4,321
  • 1
  • 24
  • 35
  • ResourcesCompat only works if the drawable is a BitmapDrawable, if you are using VectorDrawable, then you are going to have a CCE. – Brill Pappin Apr 27 '18 at 17:37
  • Neither of these work with a *VectorDrawable* resource. The following error occurs - `android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable` – AdamHurwitz Jun 08 '19 at 21:24
  • This [solution](https://stackoverflow.com/a/51742167/2253682) works well with Kotlin. – AdamHurwitz Jun 08 '19 at 21:51
57

android-ktx has Drawable.toBitmap method: https://android.github.io/android-ktx/core-ktx/androidx.graphics.drawable/android.graphics.drawable.-drawable/to-bitmap.html

From Kotlin

val bitmap = myDrawable.toBitmap()
MyDogTom
  • 4,486
  • 1
  • 28
  • 41
51

1) Drawable to Bitmap :

Bitmap mIcon = BitmapFactory.decodeResource(context.getResources(),R.drawable.icon);
// mImageView.setImageBitmap(mIcon);

2) Bitmap to Drawable :

Drawable mDrawable = new BitmapDrawable(getResources(), bitmap);
// mImageView.setDrawable(mDrawable);
Sanjayrajsinh
  • 15,014
  • 7
  • 73
  • 78
32

very simple

Bitmap tempBMP = BitmapFactory.decodeResource(getResources(),R.drawable.image);
Erfan Bagheri
  • 638
  • 1
  • 8
  • 16
  • 11
    This is just plagiarism of the [other answer](http://stackoverflow.com/a/3035869/984830) on this question three full years earlier – Nick Cardoso Mar 15 '17 at 17:34
20

The latest androidx core library (androidx.core:core-ktx:1.2.0) now has an extension function: Drawable.toBitmap(...) to convert a Drawable to a Bitmap.

Balazs Banyai
  • 676
  • 7
  • 10
  • 1
    I can't quite figure out how to import that function. I assume that it works outside of Kotlin too? – Saman Miran Oct 09 '20 at 12:35
  • 1
    From java, you need to import the Kt file containing the extension methods. Also, the signature is slightly more complex, as the receiver and the default parameters are not available in java. It will be like this: `DrawableKt.toBitmap(...);` – Balazs Banyai Oct 11 '20 at 05:20
  • Make sure to include the parameters, since java doesn't see method overloads using default parameters ```kotlin DrawableKt.toBitmap( mCornerTopLeftDrawable, mCornerTopLeftDrawable.getIntrinsicWidth(), mCornerTopLeftDrawable.getIntrinsicHeight(), null ) ``` – Tamim Attafi Aug 13 '23 at 20:09
19

So after looking (and using) of the other answers, seems they all handling ColorDrawable and PaintDrawable badly. (Especially on lollipop) seemed that Shaders were tweaked so solid blocks of colors were not handled correctly.

I am using the following code now:

public static Bitmap drawableToBitmap(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    }

    // We ask for the bounds if they have been set as they would be most
    // correct, then we check we are  > 0
    final int width = !drawable.getBounds().isEmpty() ?
            drawable.getBounds().width() : drawable.getIntrinsicWidth();

    final int height = !drawable.getBounds().isEmpty() ?
            drawable.getBounds().height() : drawable.getIntrinsicHeight();

    // Now we check we are > 0
    final Bitmap bitmap = Bitmap.createBitmap(width <= 0 ? 1 : width, height <= 0 ? 1 : height,
            Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

Unlike the others, if you call setBounds on the Drawable before asking to turn it into a bitmap, it will draw the bitmap at the correct size!

Chris.Jenkins
  • 13,051
  • 4
  • 60
  • 61
  • Wouldn't setBounds ruin the previous bounds of the drawable? Isn't it better to store it and restore it afterwards? – android developer Apr 11 '15 at 17:43
  • @androiddeveloper, if the bounds have been set, we are just using those anyway. In some cases this is needed where no bounds have been set and has no intrinsic size (such as ColorDrawables in some cases). So width and height would be 0, we give the drawable 1x1 that way it actually draws something. I could be argued we could do a type check for ColorDrawable in those cases, but this works for 99% of cases. (You can modify it for your needs). – Chris.Jenkins Apr 11 '15 at 17:48
  • @Chris.Jenkins What if it doesn't have bounds , and now it will get new ones? I'd also like to ask another question: what's the best way to set the bitmap size (even for BitmapDrawable) that gets returned ? – android developer Apr 11 '15 at 17:49
  • I suggest you carefully read the code. If the `Drawable` does not have bounds set it uses the `IntrinsicWidth/Height`. If they are both <= 0 we set the canvas to 1px. You are correct if the `Drawable` does not have bounds it will be passed some (1x1 is most cases), but this is REQUIRED for things like `ColorDrawable` which DO NOT have intrinsic sizes. If we didn't do this, it would throw an `Exception`, you can't draw 0x0 to a canvas. – Chris.Jenkins Apr 11 '15 at 17:53
  • @Chris.Jenkins I mean that before calling this function, if the drawable doesn't have bounds, after calling it, it will have. Also, please answer the other question. – android developer Apr 11 '15 at 17:54
  • Ahh I see what you mean. Yes you are correct the original Drawable will now have bounds. I guess you would need to call `mutate()` to be really safe. This is used where you want a bitmap and throw away the drawable so its never been a concern. As for Bitmap size? setting the Bounds defines how much actually gets drawn (as long as the Drawable plays nicely). But the Drawable can draw off the canvas (you just won't see it). The only true way to define the bitmap size would be to pass it in as a parameter. – Chris.Jenkins Apr 11 '15 at 17:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75021/discussion-between-chris-jenkins-and-android-developer). – Chris.Jenkins Apr 11 '15 at 18:00
  • @Chris.Jenkins What does mutate() do here? wouldn't it be easier to store the previous bounds, and set it again at the end? Can you please update the code to be more correct? Also, about the bitmap size, what you wrote is about the non-BitmapDrawable case. For BitmapDrawable, I guess you just use "createScaledBitmap" (or something similar, depends on how you want to scale) ? – android developer Apr 11 '15 at 18:49
  • 1
    `mutate()` would make a copy leaving the original drawable alone which would negate the issue of passing back in the original bounds. I am seldom to change the code based on those points. If your use case requires it add another answer. I suggest you create another question for the Bitmap scaling. – Chris.Jenkins Apr 11 '15 at 19:09
  • @Chris.Jenkins: It should be noted that mutate() does not make a copy. It instead marks it as mutable so that it doesn't affect any other drawables sharing the same ConstantState. Additionally, bounds aren't contained within ConstantState, so mutate wouldn't work in this instance. – David Liu Sep 22 '15 at 00:48
13

Here is the nice Kotlin version of the answer provided by @Chris.Jenkins here: https://stackoverflow.com/a/27543712/1016462

fun Drawable.toBitmap(): Bitmap {
  if (this is BitmapDrawable) {
    return bitmap
  }

  val width = if (bounds.isEmpty) intrinsicWidth else bounds.width()
  val height = if (bounds.isEmpty) intrinsicHeight else bounds.height()

  return Bitmap.createBitmap(width.nonZero(), height.nonZero(), Bitmap.Config.ARGB_8888).also {
    val canvas = Canvas(it)
    setBounds(0, 0, canvas.width, canvas.height)
    draw(canvas)
  }
}

private fun Int.nonZero() = if (this <= 0) 1 else this
tasomaniac
  • 10,234
  • 6
  • 52
  • 84
13

Maybe this will help someone...

From PictureDrawable to Bitmap, use:

private Bitmap pictureDrawableToBitmap(PictureDrawable pictureDrawable){ 
    Bitmap bmp = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Config.ARGB_8888); 
    Canvas canvas = new Canvas(bmp); 
    canvas.drawPicture(pictureDrawable.getPicture()); 
    return bmp; 
}

... implemented as such:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);
Mauro
  • 589
  • 5
  • 15
12

Here is better resolution

public static Bitmap drawableToBitmap (Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable)drawable).getBitmap();
    }

    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap); 
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

public static InputStream bitmapToInputStream(Bitmap bitmap) {
    int size = bitmap.getHeight() * bitmap.getRowBytes();
    ByteBuffer buffer = ByteBuffer.allocate(size);
    bitmap.copyPixelsToBuffer(buffer);
    return new ByteArrayInputStream(buffer.array());
}

Code from How to read drawable bits as InputStream

Community
  • 1
  • 1
Gelldur
  • 11,187
  • 7
  • 57
  • 68
12

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon);

This will not work every time for example if your drawable is layer list drawable then it gives a null response, so as an alternative you need to draw your drawable into canvas then save as bitmap, please refer below a cup of code.

public void drawableToBitMap(Context context, int drawable, int widthPixels, int heightPixels) {
    try {
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/", "drawable.png");
        FileOutputStream fOut = new FileOutputStream(file);
        Drawable drw = ResourcesCompat.getDrawable(context.getResources(), drawable, null);
        if (drw != null) {
            convertToBitmap(drw, widthPixels, heightPixels).compress(Bitmap.CompressFormat.PNG, 100, fOut);
        }
        fOut.flush();
        fOut.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private Bitmap convertToBitmap(Drawable drawable, int widthPixels, int heightPixels) {
    Bitmap bitmap = Bitmap.createBitmap(widthPixels, heightPixels, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, widthPixels, heightPixels);
    drawable.draw(canvas);
    return bitmap;
}

above code save you're drawable as drawable.png in the download directory

Kishan Donga
  • 2,851
  • 2
  • 23
  • 35
  • Using BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher); gives "skia -- Failed to create image decoder with message 'unimplemented'" in some devices, its better to use ContextCompat.getDrawable() and then to bitmap. – Ezequiel Adrian May 25 '23 at 22:36
8

Android provides a non straight foward solution: BitmapDrawable. To get the Bitmap , we'll have to provide the resource id R.drawable.flower_pic to the a BitmapDrawable and then cast it to a Bitmap.

Bitmap bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.flower_pic)).getBitmap();
kc ochibili
  • 3,103
  • 2
  • 25
  • 25
6

BitmapFactory.decodeResource() automatically scales the bitmap, so your bitmap may turn out fuzzy. To prevent scaling, do this:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap source = BitmapFactory.decodeResource(context.getResources(),
                                             R.drawable.resource_name, options);

or

InputStream is = context.getResources().openRawResource(R.drawable.resource_name)
bitmap = BitmapFactory.decodeStream(is);
John Doe
  • 1,003
  • 12
  • 14
5

Use this code.it will help you for achieving your goal.

 Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.profileimage);
    if (bmp!=null) {
        Bitmap bitmap_round=getRoundedShape(bmp);
        if (bitmap_round!=null) {
            profileimage.setImageBitmap(bitmap_round);
        }
    }

  public Bitmap getRoundedShape(Bitmap scaleBitmapImage) {
    int targetWidth = 100;
    int targetHeight = 100;
    Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, 
            targetHeight,Bitmap.Config.ARGB_8888);

    Canvas canvas = new Canvas(targetBitmap);
    Path path = new Path();
    path.addCircle(((float) targetWidth - 1) / 2,
            ((float) targetHeight - 1) / 2,
            (Math.min(((float) targetWidth), 
                    ((float) targetHeight)) / 2),
                    Path.Direction.CCW);

    canvas.clipPath(path);
    Bitmap sourceBitmap = scaleBitmapImage;
    canvas.drawBitmap(sourceBitmap, 
            new Rect(0, 0, sourceBitmap.getWidth(),
                    sourceBitmap.getHeight()), 
                    new Rect(0, 0, targetWidth, targetHeight), new Paint(Paint.FILTER_BITMAP_FLAG));
    return targetBitmap;
}
anupam sharma
  • 1,705
  • 17
  • 13
3

In Kotlin, the easiest way is:

Drawable.toBitmap(width: Int, height: Int, config: Bitmap.Config?): Bitmap

like this:

val bitmapResult = yourDrawable.toBitmap(1,1,null)

where, just need a drawable variable, No resource, No context, No id

Mori
  • 2,653
  • 18
  • 24
2

ImageWorker Library can convert bitmap to drawable or base64 and vice versa.

val bitmap: Bitmap? = ImageWorker.convert().drawableToBitmap(sourceDrawable)

Implementation

In Project Level Gradle

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

In Application Level Gradle

dependencies {
            implementation 'com.github.1AboveAll:ImageWorker:0.51'
    }

You can also store and retrieve bitmaps/drawables/base64 images from external.

Check here. https://github.com/1AboveAll/ImageWorker/edit/master/README.md

Himanshu Rawat
  • 658
  • 5
  • 13
2

if you are using kotlin the use below code. it'll work

// for using image path

val image = Drawable.createFromPath(path)
val bitmap = (image as BitmapDrawable).bitmap
1
 // get image path from gallery
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
    super.onActivityResult(requestCode, resultcode, intent);

    if (requestCode == 1) {
        if (intent != null && resultcode == RESULT_OK) {             
            Uri selectedImage = intent.getData();

            String[] filePathColumn = {MediaStore.Images.Media.DATA};
            Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            filePath = cursor.getString(columnIndex);

            //display image using BitmapFactory

            cursor.close(); bmp = BitmapFactory.decodeFile(filepath); 
            iv.setBackgroundResource(0);
            iv.setImageBitmap(bmp);
        }
    }
}
Ziem
  • 6,579
  • 8
  • 53
  • 86
Angel
  • 143
  • 1
  • 4
  • I think you read the question wrong. The question asks: how to get a bitmap from a drawable resource not system gallery – kc ochibili May 29 '14 at 11:30
1

I've used a few answers on this thread but some of them didn't work as expected (maybe they had worked in older versions) but I wanted to share mine after a few tries and errors, using an extension function:

val markerOption = MarkerOptions().apply {
    position(LatLng(driver.lat, driver.lng))
    icon(R.drawabel.your_drawable.toBitmapDescriptor(context))
    snippet(driver.driverId.toString())
}
mMap.addMarker(markerOption)

This is the extension function:

fun Int.toBitmapDescriptor(context: Context): BitmapDescriptor {
    val vectorDrawable = ResourcesCompat.getDrawable(context.resources, this, context.theme)
    val bitmap = vectorDrawable?.toBitmap(
        vectorDrawable.intrinsicWidth,
        vectorDrawable.intrinsicHeight,
        Bitmap.Config.ARGB_8888
    )
    return BitmapDescriptorFactory.fromBitmap(bitmap!!)
}
Alberto
  • 426
  • 6
  • 16