Bitmap vom Vektor zeichnen lassen


132

In meiner Anwendung muss ich ein großes Symbol für eine Benachrichtigung festlegen. LargeIcon muss eine Bitmap sein, und meine Zeichen sind Vektorgrafiken (die neue Funktion in Android, siehe diesen Link ). Das Problem ist, wenn ich versuche, eine Ressource zu dekodieren, die ein Vektorbild ist, wird eine Null zurückgegeben.

Hier ist das Codebeispiel:

if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null)
        Log.d("ISNULL", "NULL");
    else
        Log.d("ISNULL", "NOT NULL");

Wenn ich in diesem Beispiel R.drawable.vector_menu_objectifs durch ein "normales" Bild ersetze, beispielsweise ein PNG, ist das Ergebnis nicht null (ich erhalte die richtige Bitmap). Fehlt etwas?


1
Hatte ein ähnliches Problem, keine Lösung, aber eine Problemumgehung
als

Antworten:


231

Geprüft auf 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;
}

AKTUALISIEREN:

Projektgradle:

dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0-alpha5'
    }

Modul gradle:

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.3'
    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 23
        vectorDrawables.useSupportLibrary = true
    }
    ...
}
...

Danke dir. Vorherige Antwort funktioniert nicht mit SDK-Version ab 23
Paha

2
Das funktioniert gut für mich. Läuft auf API 15 ohne Probleme
Vera

4
AppCompatDrawableManagerist als @RestrictTo(LIBRARY_GROUP)intern gekennzeichnet und sollte nicht verwendet werden (die API kann ohne vorherige Ankündigung geändert werden). Verwenden Sie ContextCompatstattdessen.
mradzinski

funktioniert nicht Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object referencein dieser ZeileBitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
user25

5
Ich hatte Probleme mit dieser Lösung. Bei Verwendung von: AppCompatResources anstelle von ContextCompat wurde Folgendes behoben: Drawable drawable = AppCompatResources.getDrawable (context, drawableId);
Mike T

64

Sie können die folgende Methode verwenden:

@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;
}

was ich manchmal kombiniere mit:

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

2
hoffentlich kommt @liltof zurück und markiert dies als Antwort. Die eine Sache zu beachten ist, dass beide Methoden den targetAPi-Wrapper wollen - aber Android Studio wird Ihnen das sagen.
Roberto Tomás

1
Ich habe ungefähr zwei Tage damit verbracht, dies zu versuchen, jetzt über das Problem mit der SVG-Datei nachgedacht. Danke dir!
sparkly_frog

1
funktioniert nicht Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object referencein dieser ZeileBitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
user25

45

Wenn Sie bereit sind, Android KTX für Kotlin zu verwenden, können Sie die Erweiterungsmethode verwenden Drawable#toBitmap(), um den gleichen Effekt wie bei den anderen Antworten zu erzielen:

val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap() 

oder

val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap() 

Um diese und andere nützliche Erweiterungsmethoden hinzuzufügen, müssen Sie Ihrer Modulebene Folgendes hinzufügen build.gradle

repositories {
    google()
}

dependencies {
    implementation "androidx.core:core-ktx:1.2.0"
}

Sehen Sie hier für die neuesten Anleitungen zum Hinzufügen der Abhängigkeit zu Ihrem Projekt.

Beachten Sie, dass dies für jede Unterklasse von funktioniert. DrawableWenn dies Drawableeine BitmapDrawableVerknüpfung ist, wird die zugrunde liegende Verknüpfung verwendet Bitmap.


Dies ist hier die einfachste Lösung für Kotlin.
Adam Hurwitz

1
Für mich funktioniert es perfekt mit VectorDrawable.
Ubuntudroid

Dies ist die beste Option. Standard AndroidX bietet Funktionalität
Reshma

27

Basierend auf den vorherigen Antworten kann es so vereinfacht werden, dass es sowohl mit VectorDrawable als auch mit BitmapDrawable übereinstimmt und mit mindestens API 15 kompatibel ist.

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

Dann müssen Sie in Ihre Gradle-Datei hinzufügen:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

Auf Pre-Lollipop wird VectorDrawableCompat und auf Lollipop VectorDrawable verwendet.

BEARBEITEN

Ich habe die Bedingung nach dem Kommentar von @ user3109468 bearbeitet


1
Zeicheninstanz von VectorDrawable || Bei einer zeichnbaren Instanz von VectorDrawableCompat sollten die Seiten vertauscht werden. Ergebnisse in einer Klasse, die nicht gefunden wird, wenn VectorDrawable nicht vorhanden ist, wenn VectorDrawableCompat zuerst überprüft werden sollte, da es vorhanden ist.
Warrick

Die Typprüfung von VertorDrawable kann als(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable)
chmin

6

Ein großes Lob an @Alexey

Hier ist die KotlinVersion mit Erweiterungen zuContext

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
}

Anwendungsbeispiel in Activity:

val bitmap = this.getBitmapFromVectorDrawable(R.drawable.ic_done_white_24dp)

1

Getestet auf API 16 - JellyBean mit Vector Drawables

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;
}   

1

Verwenden Sie den folgenden Code, um Bilder mit dem richtigen Seitenverhältnis zu konvertieren (z. B. für das Benachrichtigungssymbol):

public static Bitmap getBitmapFromVector(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();
    Bitmap bitmap;
    if (width < height) {    //make a square
        bitmap = Bitmap.createBitmap(height, height, Bitmap.Config.ARGB_8888);
    } else {
        bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
    }
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0,
            drawable.getIntrinsicWidth(),    //use dimensions of Drawable
            drawable.getIntrinsicHeight()
    );
    drawable.draw(canvas);
    return bitmap;
}

0

Wenn Ihr vectorBild intrinsicWidthund intrinsicHeightklein ist und Sie versuchen , die Bitmap in eine Großansicht angezeigt werden , dann werden Sie sehen das Ergebnis Unschärfe ist.

In diesem Fall können Sie eine neue Breite / Höhe für Ihre Bitmap angeben, um ein besseres Bild zu erhalten (oder Sie können die Vektorgröße in XML erhöhen, aber die desireWidthund desireHeightmöglicherweise flexibler angeben).

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
}

Hoffe es hilft


0
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

Wenn Sie Ihre Ausgabe auf die gewünschte Ausgabegröße skalieren möchten, versuchen Sie das folgende 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)

0

Dadurch erhalten Sie die Bitmap in der gewünschten Größe. Darüber hinaus können Sie die Transparenz je nach Bild beibehalten oder nicht, um eine bessere Leistung bei denjenigen zu erzielen, die sie nicht benötigen.

public static Bitmap drawableToBitmap(Resources res, int drawableId,
        int width, int height, boolean keepAlpha) {
    Drawable drawable = res.getDrawable(drawableId);
    Bitmap bmp = createBitmap(width, height, keepAlpha ?
            Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
    Canvas cvs = new Canvas(bmp);
    drawable.setBounds(0, 0, width, height);
    drawable.draw(cvs);
    return bmp;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.