web-dev-qa-db-fra.com

Obtenir des images bitmap à partir de vecteur

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?

87
liltof

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
    }
    ...
}
...
154
Alexey

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");
    }
}
57
snodnipper

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.

MODIFIER

J'ai modifié la condition à la suite du commentaire de @ user3109468

21
Eselfar

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.

9
David Rawson

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)
3
Gunhan

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 !

0
tomasmark79
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));

0
Amine

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

0
Linh

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)
0
Hans