Dans mon application, je dois définir une grande icône pour une notification . LargeIcon doit être une bitmap, et mes éléments dessinables sont des images vectorielles (la nouvelle fonctionnalité dans Android, voir ce lien ) Le problème c’est quand j’essaie de décoder une ressource qui est une image vectorielle que j’obtiens un null retourné.
Voici l'exemple de code:
if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null)
Log.d("ISNULL", "NULL");
else
Log.d("ISNULL", "NOT NULL");
Dans cet exemple, lorsque je remplace R.drawable.vector_menu_objectifs par une image "normale", un png par exemple, le résultat n'est pas nul (le bitmap correct est obtenu) Quelque chose me manque-t-il?
Vérifié sur 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;
}
METTRE À JOUR:
Niveau de projet:
dependencies {
classpath 'com.Android.tools.build:gradle:2.2.0-alpha5'
}
Grade du module:
Android {
compileSdkVersion 23
buildToolsVersion '23.0.3'
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
vectorDrawables.useSupportLibrary = true
}
...
}
...
Vous pouvez utiliser la méthode suivante:
@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;
}
que je combine parfois avec:
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");
}
}
Sur la base des réponses précédentes, il peut être simplifié de la sorte pour faire correspondre VectorDrawable et BitmapDrawable et pour être compatible avec au moins 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");
}
}
Ensuite, vous devez ajouter dans votre fichier gradle:
Android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
Avant la sucette, il utilisera VectorDrawableCompat et sur Lollipop, il utilisera VectorDrawable.
J'ai modifié la condition à la suite du commentaire de @ user3109468
Si vous souhaitez utiliser Android KTX pour Kotlin, vous pouvez utiliser la méthode d'extension Drawable#toBitmap()
pour obtenir le même effet que les autres réponses:
val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap()
ou
val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap()
Pour ajouter ceci et d'autres méthodes d'extension utiles, vous devrez ajouter les éléments suivants à votre build.gradle
au niveau du module
repositories {
google()
}
dependencies {
implementation 'androidx.core:core-ktx:1.0.0-alpha1'
}
Lien vers la source de la méthode d'extension ici .
Notez que cela fonctionnera pour toutes les sous-classes de Drawable
et si le Drawable
est un BitmapDrawable
, il utilisera la variable Bitmap
sous-jacente.
Félicitations à @Alexey
Voici la version Kotlin
utilisant les extensions à 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
}
Exemple d'utilisation dans Activity
:
val bitmap = this.getBitmapFromVectorDrawable(R.drawable.ic_done_white_24dp)
Testé sur API 16 - JellyBean avec des éléments vectoriels
public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
Drawable drawable = AppCompatResources.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;
Merci à tous !
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));
Si votre vector
image intrinsicWidth
et intrinsicHeight
est petite et que vous essayez d'afficher le bitmap dans une vue agrandie, vous verrez alors que le résultat est flou.
Dans ce cas, vous pouvez fournir une nouvelle largeur/hauteur à votre bitmap pour obtenir la meilleure image (ou vous pouvez augmenter la taille du vecteur en xml, mais indiquez que desireWidth
et desireHeight
peuvent être plus souples).
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
}
J'espère que ça aide
Si vous souhaitez pouvoir mettre à l'échelle votre sortie à la taille de sortie souhaitée, essayez l'extrait suivant:
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)