In my application, I have to set a large icon for a notification. LargeIcon must be a Bitmap, and my drawables are vector images (the new feature in Android, see this link) The problem is when I try to decode a resource that is a vector image, I get a null returned.
Here is the sample of code :
if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null)
Log.d("ISNULL", "NULL");
else
Log.d("ISNULL", "NOT NULL");
In this sample, when I replace R.drawable.vector_menu_objectifs with a "normal" image, a png for exemple, the result is not null (I get the correct bitmap) Is there something I'm missing?
Checked on API: 17, 21, 23
public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawable = (DrawableCompat.wrap(drawable)).mutate();
}
Bitmap 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;
}
UPDATE:
Project gradle:
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0-alpha5'
}
Module gradle:
android {
compileSdkVersion 23
buildToolsVersion '23.0.3'
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
vectorDrawables.useSupportLibrary = true
}
...
}
...
You can use the following method:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vectorDrawable.draw(canvas);
return bitmap;
}
which I sometimes combine with:
private static Bitmap getBitmap(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof VectorDrawable) {
return getBitmap((VectorDrawable) drawable);
} else {
throw new IllegalArgumentException("unsupported drawable type");
}
}
Based on the previous answers it can be simplified like that to match both VectorDrawable and BitmapDrawable and to be compatible with at least API 15.
public static Bitmap getBitmapFromDrawable(Context context, @DrawableRes int drawableId) {
Drawable drawable = AppCompatResources.getDrawable(context, drawableId);
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof VectorDrawableCompat || drawable instanceof VectorDrawable) {
Bitmap 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;
} else {
throw new IllegalArgumentException("unsupported drawable type");
}
}
Then you have to add in your gradle file:
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
On pre-Lollipop it will use VectorDrawableCompat and on Lollipop it will use VectorDrawable.
EDIT
I've edited the condition following the comment of @user3109468
If you are willing to use Android KTX for Kotlin you can use the extension method Drawable#toBitmap()
to achieve the same effect as the other answers:
val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap()
or
val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap()
To add this and other useful extension methods you will need to add the following to your module-level build.gradle
repositories {
google()
}
dependencies {
implementation 'androidx.core:core-ktx:1.0.0-alpha1'
}
Note that this will work for any subclass of Drawable
and if the Drawable
is a BitmapDrawable
it will shortcut to use the underlying Bitmap
.
Kudos to @Alexey
Here is the Kotlin
version using extensions to Context
fun Context.getBitmapFromVectorDrawable(drawableId: Int): Bitmap? {
var drawable = ContextCompat.getDrawable(this, drawableId) ?: return null
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawable = DrawableCompat.wrap(drawable).mutate()
}
val bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888) ?: return null
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
Example usage in Activity
:
val bitmap = this.getBitmapFromVectorDrawable(R.drawable.ic_done_white_24dp)
If your vector
image intrinsicWidth
and intrinsicHeight
is small and you try to display the bitmap to a big view, then you will see the result is blur.
In that case, you can provide a new width/height for your bitmap to get the better image (or you can increase the vector size in xml, but provide the desireWidth
and desireHeight
may be more flexible).
private fun getBitmap(drawableId: Int, desireWidth: Int? = null, desireHeight: Int? = null): Bitmap? {
val drawable = AppCompatResources.getDrawable(context, drawableId) ?: return null
val bitmap = Bitmap.createBitmap(
desireWidth ?: drawable.intrinsicWidth,
desireHeight ?: drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
Hope it help
Drawable layerDrawable = (Drawable) imageBase.getDrawable();
Bitmap bitmap = Bitmap.createBitmap(layerDrawable.getIntrinsicWidth(),
layerDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
layerDrawable.draw(canvas);
imageTeste.setImageBitmap(addGradient(bitmap));
If you want to be able to scale your output to a desired output size, try the following snippet:
fun getBitmapFromVectorDrawable(context: Context, drawableId: Int, outputSize: OutputSize? = null): Bitmap? {
var drawable = ContextCompat.getDrawable(context, drawableId) ?: return null
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawable = DrawableCompat.wrap(drawable).mutate()
}
var targetBitmap: Bitmap
if (outputSize != null) {
targetBitmap = Bitmap.createBitmap(outputSize.width,
outputSize.height, Bitmap.Config.ARGB_8888)
} else {
targetBitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
}
val canvas = Canvas(targetBitmap)
val scaleX = targetBitmap.width.toFloat()/drawable.intrinsicWidth.toFloat()
val scaleY = targetBitmap.height.toFloat()/drawable.intrinsicHeight.toFloat()
canvas.scale(scaleX, scaleY)
drawable.draw(canvas)
return targetBitmap
}
class OutputSize(val width: Int, val height: Int)
来源:https://stackoverflow.com/questions/33696488/getting-bitmap-from-vector-drawable