Wie konvertiere ich ein Drawable in eine Bitmap?


947

Ich möchte ein bestimmtes DrawableHintergrundbild für das Gerät festlegen , aber alle Hintergrundbildfunktionen akzeptieren Bitmapnur s. Ich kann nicht verwenden, WallpaperManagerweil ich vor 2.1 bin.

Außerdem werden meine Drawables aus dem Internet heruntergeladen und befinden sich nicht in R.drawable.



1
Bitte wählen Sie die richtige Antwort: stackoverflow.com/a/3035869/4548520
user25

Antworten:


1289

Dieser Code hilft.

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

Hier eine Version, in der das Bild heruntergeladen wird.

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

1
Ich denke, Sie haben die URL-Werte. dann sollte meine bearbeitete Antwort helfen.
Praveen

Woher kommt str_url? Ich konnte keine Drawable-Funktion für Strings finden ... danke für Ihre Hilfe.
Rob

12
Ich glaube, ich habe etwas gefunden: Wenn "draw" das Drawable ist, das ich in eine Bitmap konvertieren möchte, dann: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); macht den Trick!
Rob

1
@Rob: Wenn dein Drawable nur ein BitmapDrawable ist. (was bedeutet, dass Ihr Drawable eigentlich nur ein Wrapper um eine Bitmap ist)
njzk2

2
Hinweis: Dies verursacht massiven java.lang.OutOfMemoryError mit JPGs
Jemand irgendwo

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

41
Dies scheint die einzige Antwort zu sein, die für jede Art von Zeichen funktioniert, und bietet auch eine schnelle Lösung für ein Zeichen, das bereits ein BitmapDrawable ist. +1
Matt Wolfe

1
Nur eine Änderung: docs sagt über BitmapDrawable.getBitmap (), dass es möglicherweise null zurückkommt. Ich sage, es kann auch schon recycelt zurückkommen.
Kellogs

16
Achtung: getIntrinsicWidth()und getIntrinsicHieght()gibt -1 zurück, wenn Drawable einfarbig ist.
SD

5
Also ... noch ein Check für ColorDrawable, und wir haben einen Gewinner. Im Ernst, jemand macht dies zur akzeptierten Antwort.
Kaay

2
Im Gegensatz zur gekennzeichneten Antwort beantwortet dies die Frage.
NJZK2

214

Dadurch wird eine BitmapDrawable in eine Bitmap konvertiert.

Drawable d = ImagesArrayList.get(0);  
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();

9
ist das wirklich der beste Weg? Sicherlich könnte das Drawable von einem anderen Typ sein und dies würde eine runtimeException auslösen? Zum Beispiel könnte es ein NinePatchDrawble sein ...?
Dori

4
@ Dori Sie könnten den Code in eine bedingte Anweisung einschließen, um zu überprüfen, ob es tatsächlich ein ist, BitmapDrawablebevor Sie ihn wirken: if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Tony Chan

367
Kannst du die 64 Upvotes nicht glauben? Dieser Code funktioniert offensichtlich nur, wenn er dbereits ein Code istBitmapDrawable . In diesem Fall ist es trivial, ihn als Bitmap abzurufen. ClassCastExceptionIn allen anderen Fällen stürzt er ab .
Matthias

3
@ Matthias nicht zu erwähnen, dass .. die Frage selbst, derselbe Autor, hat 100 Stimmen: /
Quinestor

2
Dies ist so spezialisiert auf einen trivialen Fall.
NJZK2

141

A Drawablekann auf a gezeichnet Canvaswerden und a Canvaskann durch a unterstützt werden Bitmap:

(Aktualisiert, um eine schnelle Konvertierung für BitmapDrawables durchzuführen und sicherzustellen, dass die Bitmaperstellte Größe eine gültige Größe hat.)

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

Was passiert, wenn der zeichnbare Parameter null ist?
hrules6872

1
Diese Methode unterstützt nicht VectorDrawable
Mahmoud


Angenommen, Sie erhalten ein nicht leeres Drawable. Warum muss überprüft werden, ob Breite und Höhe nicht 0 sind? Warum müssen Sie setBounds () verwenden, wenn sie dieselbe Größe haben?
Yoav Feuerstein

Gute Lösung! Android 8.0 / sdk 26 ApplicationInfo.loadIcon (PackageManager pm) gibt ein AdaptiveIconDrawable zurück。 Verwenden Sie Ihren Code, um AdaptiveIconDrawable in Bitmap
umzuwandeln

43

METHODE 1 : Entweder können Sie direkt in eine Bitmap wie diese konvertieren

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

METHODE 2 : Sie können die Ressource sogar in eine Zeichnungsdatei konvertieren und daraus eine Bitmap wie diese erhalten

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

Für API> 22 wurde die getDrawable Methode in die ResourcesCompatKlasse verschoben, damit Sie so etwas tun

Bitmap myLogo = ((BitmapDrawable) ResourcesCompat.getDrawable(context.getResources(), R.drawable.logo, null)).getBitmap();

ResourcesCompat funktioniert nur, wenn das Drawable ein BitmapDrawable ist. Wenn Sie VectorDrawable verwenden, verfügen Sie über ein CCE.
Brill Pappin

Beides funktioniert nicht mit einer VectorDrawable- Ressource. Der folgende Fehler tritt auf -android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz

Diese Lösung funktioniert gut mit Kotlin.
Adam Hurwitz


15

Nach dem Betrachten (und Verwenden) der anderen Antworten scheinen sie alle schlecht ColorDrawableund PaintDrawableschlecht zu handhaben . (Besonders bei Lutschern) schien, dass Shaders so optimiert wurden, dass feste Farbblöcke nicht richtig gehandhabt wurden.

Ich verwende jetzt den folgenden Code:

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

Im Gegensatz zu den anderen wird die Bitmap in der richtigen Größe gezeichnet , wenn Sie setBoundsdie Drawablevorherige Aufforderung zur Umwandlung in eine Bitmap aufrufen !


Würde setBounds nicht die vorherigen Grenzen des Drawable ruinieren? Ist es nicht besser, es zu speichern und anschließend wiederherzustellen?
Android-Entwickler

@androiddeveloper, wenn die Grenzen gesetzt wurden, verwenden wir diese sowieso nur. In einigen Fällen ist dies erforderlich, wenn keine Grenzen festgelegt wurden und keine intrinsische Größe haben (z. B. in einigen Fällen ColorDrawables). Breite und Höhe wären also 0, wir geben dem Zeichen 1x1 so, dass es tatsächlich etwas zeichnet. Ich könnte argumentieren, dass wir in diesen Fällen eine Typprüfung für ColorDrawable durchführen könnten, aber dies funktioniert in 99% der Fälle. (Sie können es für Ihre Bedürfnisse ändern).
Chris.Jenkins

@ Chris.Jenkins Was ist, wenn es keine Grenzen hat und jetzt neue werden? Ich möchte auch eine andere Frage stellen: Wie kann die zurückgegebene Bitmap-Größe (auch für BitmapDrawable) am besten festgelegt werden?
Android-Entwickler

Ich schlage vor, dass Sie den Code sorgfältig lesen. Wenn für das Drawablekeine Grenzen festgelegt sind, wird das verwendet IntrinsicWidth/Height. Wenn beide <= 0 sind, setzen wir die Zeichenfläche auf 1px. Sie haben Recht, wenn das Drawablekeine Grenzen hat, wird es einige übergeben (1x1 ist in den meisten Fällen), aber dies ist für Dinge wie solche erforderlich, ColorDrawabledie KEINE intrinsischen Größen haben. Wenn wir dies nicht tun würden, würde es ein werfen Exception, Sie können 0x0 nicht auf eine Leinwand zeichnen.
Chris.Jenkins

1
mutate()würde eine Kopie erstellen, die das Original in Ruhe lässt, was das Problem der Rückgabe in die ursprünglichen Grenzen zunichte machen würde. Ich ändere den Code selten basierend auf diesen Punkten. Wenn Ihr Anwendungsfall dies erfordert, fügen Sie eine weitere Antwort hinzu. Ich schlage vor, Sie erstellen eine weitere Frage für die Bitmap-Skalierung.
Chris.Jenkins

13

Vielleicht hilft das jemandem ...

Verwenden Sie von PictureDrawable zu Bitmap:

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

... als solche implementiert:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);

Wie bei Robs Antwort benötigen Sie eine bestimmte Art von Drawable, in diesem Fall a PictureDrawable.
Kabuko

4
"Vielleicht hilft das jemandem ..."
Mauro

11

Hier ist eine bessere Auflösung

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 aus Wie man zeichnbare Bits als InputStream liest


11

1) auf Bitmap zeichnbar:

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

2) Bitmap zu Drawable:

Drawable mDrawable = new BitmapDrawable(getResources(), bitmap);
// mImageView.setDrawable(mDrawable);

10

Hier ist die nette Kotlin-Version der Antwort von @ Chris.Jenkins hier: 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


8

Android bietet eine nicht gerade Vorwärtslösung : BitmapDrawable. Um die Bitmap zu erhalten, müssen wir die Ressourcen-ID R.drawable.flower_picfür a angeben BitmapDrawableund sie dann in a umwandeln Bitmap.

Bitmap bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.flower_pic)).getBitmap();

5

Verwenden Sie diesen Code. Er hilft Ihnen beim Erreichen Ihres Ziels.

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

3

BitmapFactory.decodeResource()Skaliert die Bitmap automatisch, sodass Ihre Bitmap möglicherweise unscharf wird. Gehen Sie folgendermaßen vor, um eine Skalierung zu verhindern:

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

oder

InputStream is = context.getResources().openRawResource(R.drawable.resource_name)
bitmap = BitmapFactory.decodeStream(is);

2

Wenn Sie Kotlin verwenden, verwenden Sie den folgenden Code. es wird funktionieren

// zur Verwendung des Bildpfads

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

Ich denke, Sie haben die Frage falsch gelesen. Die Frage lautet: Wie bekomme ich eine Bitmap von einer zeichnbaren Ressource, nicht von einer Systemgalerie?
kc ochibili

1

ImageWorker Library kann Bitmap in Drawable oder Base64 konvertieren und umgekehrt.

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

Implementierung

In Projektebene Gradle

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

In Application Level Gradle

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

Sie können Bitmaps / Drawables / Base64-Bilder auch von außen speichern und abrufen.

Überprüfe hier. https://github.com/1AboveAll/ImageWorker/edit/master/README.md

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.