Comment convertir un Drawable en un Bitmap?


949

Je voudrais définir un certain Drawablecomme fond d'écran de l'appareil, mais toutes les fonctions de fond d'écran acceptent Bitmapuniquement les s. Je ne peux pas l'utiliser WallpaperManagercar je suis pré 2.1.

De plus, mes drawables sont téléchargés sur le Web et ne résident pas R.drawable.



1
veuillez choisir la bonne réponse, ceci: stackoverflow.com/a/3035869/4548520
user25

Réponses:


1290

Ce morceau de code aide.

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

Voici une version où l'image est téléchargée.

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
je pense que vous avez les valeurs URL. alors ma réponse modifiée devrait aider.
Praveen

d'où vient str_url? Je n'ai trouvé aucune fonction Drawable liée aux chaînes ... merci pour votre aide.
Rob

12
Je pense avoir trouvé quelque chose: si "draw" est le dessinable que je veux convertir en bitmap, alors: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); fait l'affaire!
Rob

1
@Rob: si votre Drawable est un BitmapDrawable uniquement. (ce qui signifie que votre Drawable n'est qu'un wrapper autour d'un Bitmap, en fait)
njzk2

2
note: cela provoque une énorme java.lang.OutOfMemoryError avec JPG
Someone Somewhere

745
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
Cela ressemble à la seule réponse qui fonctionnerait pour tout type de dessin et a également une solution rapide pour un dessin qui est déjà un BitmapDrawable. +1
Matt Wolfe

1
juste un amendement: docs dit à propos de BitmapDrawable.getBitmap () qu'il peut revenir nul. Je dis qu'il peut aussi revenir déjà recyclé.
kellogs

16
Attention: getIntrinsicWidth()et getIntrinsicHieght()retournera -1 si drawable est de couleur unie.
SD

5
Alors ... un autre chèque pour ColorDrawable, et nous avons un gagnant. Sérieusement, quelqu'un en fait la réponse acceptée.
kaay

2
Contrairement à la réponse signalée, cela répond à la question.
njzk2

214

Cela convertit un BitmapDrawable en un Bitmap.

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

9
est-ce vraiment le meilleur moyen? Le drawable pourrait sûrement être d'un autre type et cela lancerait une runtimeException? Par exemple, cela pourrait être un ninePatchDrawble ...?
Dori

4
@Dori, vous pouvez envelopper le code dans une déclaration conditionnelle pour vérifier s'il s'agit bien d'un BitmapDrawableavant de le lancer: if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Tony Chan

367
Vous ne pouvez pas croire les 64 votes positifs? Ce code fonctionne évidemment que si ddéjà est un BitmapDrawable, auquel cas il est trivial de le récupérer sous forme de bitmap ... se bloque avec ClassCastExceptiondans tous les autres cas.
Matthias

3
@Matthias pour ne pas mentionner que .. la question elle-même, même auteur, a 100 votes: /
quinestor

2
C'est tellement spécialisé dans un cas trivial.
njzk2

141

Un Drawablepeut être dessiné sur un Canvas, et un Canvaspeut être soutenu par un Bitmap:

(Mis à jour pour gérer une conversion rapide pour BitmapDrawables et pour s'assurer que le Bitmapcréé a une taille valide)

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

Que se passe-t-il si le paramètre drawable est nul?
hrules6872

1
Cette méthode ne prend pas en charge VectorDrawable
Mahmoud


En supposant que vous obtenez un Drawable non vide, pourquoi est-il nécessaire de vérifier que la largeur et la hauteur ne sont pas nulles? Aussi, pourquoi avez-vous besoin d'utiliser setBounds () s'ils sont de la même taille?
Yoav Feuerstein

Bonne solution! Android 8.0 / sdk 26 ApplicationInfo.loadIcon (PackageManager pm) renvoyer un AdaptiveIconDrawable。 Utilisez votre code peut m'aider à
convertir

44

MÉTHODE 1 : Soit vous pouvez directement convertir en bitmap comme celui-ci

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

MÉTHODE 2 : Vous pouvez même convertir la ressource en dessin et à partir de là, vous pouvez obtenir un bitmap comme celui-ci

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

Pour la méthode API> 22 getDrawable déplacée dans la ResourcesCompatclasse, pour cela vous faites quelque chose comme ça

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

ResourcesCompat ne fonctionne que si le dessinable est un BitmapDrawable, si vous utilisez VectorDrawable, alors vous allez avoir un CCE.
Brill Pappin

Aucun de ces éléments ne fonctionne avec une ressource VectorDrawable . L'erreur suivante se produit -android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz

Cette solution fonctionne bien avec Kotlin.
Adam Hurwitz


15

Donc, après avoir regardé (et utilisé) les autres réponses, il semble qu'elles se comportent toutes ColorDrawableet PaintDrawablemal. (Surtout sur la sucette) semblait queShader s étaient modifiés donc les blocs de couleurs solides n'étaient pas manipulés correctement.

J'utilise maintenant le code suivant:

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

Contrairement aux autres, si vous faites appel setBoundsà Drawableavant de demander de le transformer en bitmap, il dessinera le bitmap à la bonne taille!


SetBounds ne ruinerait-il pas les limites précédentes du drawable? N'est-il pas préférable de le stocker et de le restaurer ensuite?
développeur Android

@androiddeveloper, si les limites ont été définies, nous les utilisons de toute façon. Dans certains cas, cela est nécessaire lorsqu'aucune limite n'a été définie et n'a pas de taille intrinsèque (comme ColorDrawables dans certains cas). Donc, la largeur et la hauteur seraient égales à 0, nous donnons au 1x1 dessinable de cette façon qu'il dessine réellement quelque chose. Je pourrais dire que nous pourrions faire une vérification de type pour ColorDrawable dans ces cas, mais cela fonctionne pour 99% des cas. (Vous pouvez le modifier selon vos besoins).
Chris.Jenkins

@ Chris.Jenkins Et s'il n'a pas de limites, et maintenant il en aura de nouvelles? J'aimerais également poser une autre question: quelle est la meilleure façon de définir la taille du bitmap (même pour BitmapDrawable) qui est renvoyée?
développeur Android

Je vous suggère de lire attentivement le code. Si le Drawablen'a pas de limites définies, il utilise le IntrinsicWidth/Height. S'ils sont tous les deux <= 0, nous définissons le canevas sur 1 px. Vous avez raison si le Drawablen'a pas de limites, il en sera transmis (1x1 dans la plupart des cas), mais cela est REQUIS pour des choses comme celles ColorDrawablequi n'ont PAS de tailles intrinsèques. Si nous ne le faisions pas, cela lancerait un Exception, vous ne pouvez pas dessiner 0x0 sur un canevas.
Chris.Jenkins

1
mutate()ferait une copie en laissant l'original dessinable seul, ce qui éliminerait le problème du retour dans les limites d'origine. Je dois rarement changer le code en fonction de ces points. Si votre cas d'utilisation l'exige, ajoutez une autre réponse. Je vous suggère de créer une autre question pour la mise à l'échelle Bitmap.
Chris.Jenkins

13

Peut-être que cela aidera quelqu'un ...

De PictureDrawable à Bitmap, utilisez:

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

... mis en œuvre comme tel:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);

Comme pour la réponse de Rob, vous avez besoin d'un type spécifique de Drawable, dans ce cas a PictureDrawable.
kabuko

4
"Peut-être que cela aidera quelqu'un ..."
Mauro

11

Voici une meilleure résolution

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 de Comment lire les bits dessinables comme InputStream


11

1) dessinable sur Bitmap:

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

2) bitmap à Drawable:

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

10

Voici la belle version Kotlin de la réponse fournie par @ Chris.Jenkins ici: 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 fournit une solution foward non linéaire: BitmapDrawable. Pour obtenir le bitmap, nous devons fournir l'ID de ressource R.drawable.flower_picà l'un BitmapDrawable, puis le convertir en a Bitmap.

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

5

Utilisez ce code.it vous aidera à atteindre votre objectif.

 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()redimensionne automatiquement le bitmap, de sorte que votre bitmap peut devenir flou. Pour éviter la mise à l'échelle, procédez comme suit:

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

ou

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


2

si vous utilisez kotlin, utilisez le code ci-dessous. ça va marcher

// pour utiliser le chemin de l'image

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

Je pense que vous avez mal lu la question. La question demande: comment obtenir un bitmap à partir d'une ressource dessinable et non d'une galerie système
kc ochibili

1

La bibliothèque ImageWorker peut convertir un bitmap en dessinable ou en base64 et vice versa.

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

la mise en oeuvre

Au niveau du projet Gradle

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

Au niveau de l'application Gradle

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

Vous pouvez également stocker et récupérer des images bitmaps / drawables / base64 de l'extérieur.

Vérifier ici. https://github.com/1AboveAll/ImageWorker/edit/master/README.md

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.