Come convertire un Drawable in un Bitmap?


949

Vorrei impostare un determinato Drawablecome sfondo del dispositivo, ma tutte le funzioni dello sfondo accettano Bitmapsolo s. Non posso usare WallpaperManagerperché sono pre 2.1.

Inoltre, i miei disegni estraibili vengono scaricati dal Web e non risiedono R.drawable.



1
si prega di scegliere la risposta giusta, questo: stackoverflow.com/a/3035869/4548520
user25

Risposte:


1290

Questo pezzo di codice aiuta.

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

Qui una versione in cui l'immagine viene scaricata.

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
penso che tu abbia i valori url. allora la mia risposta modificata dovrebbe aiutare.
Praveen,

da dove viene str_url? Non sono riuscito a trovare alcuna funzione Drawable correlata alle stringhe ... grazie per il vostro aiuto.
Rob,

12
Penso di aver trovato qualcosa: se "draw" è il disegno che voglio convertire in bitmap, allora: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); fa il trucco!
Rob,

1
@Rob: se il tuo Drawable è solo BitmapDrawable. (il che significa che il tuo Drawable non è altro che un wrapper attorno a una Bitmap, in realtà)
njzk2,

2
nota: questo causa un enorme java.lang.OutOfMemoryError con JPG's
Someone Somewhere

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
Questa sembra l'unica risposta che funzionerebbe per qualsiasi tipo di disegno e ha anche una soluzione rapida per un disegno che è già un BitmapDrawable. +1
Matt Wolfe,

1
solo un emendamento: docs dice di BitmapDrawable.getBitmap () che potrebbe tornare nullo. Dico che potrebbe anche tornare già riciclato.
Kellogs,

16
Attenzione: getIntrinsicWidth()e getIntrinsicHieght()restituirà -1 se il disegno è un colore solido.
SD

5
Quindi ... un altro controllo per ColorDrawable e abbiamo un vincitore. Seriamente, qualcuno rende questa la risposta accettata.
Kaay

2
Contrariamente alla risposta contrassegnata, questo risponde alla domanda.
njzk2,

214

Questo converte un BitmapDrawable in un Bitmap.

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

9
è davvero il modo migliore? Sicuramente il drawable potrebbe essere di un altro tipo e questo genererebbe una runtimeException? Ad esempio potrebbe essere un ninePatchDrawble ...?
Dori,

4
@Dori potresti racchiudere il codice in una dichiarazione condizionale per verificare se è effettivamente un BitmapDrawableprima di lanciarlo: if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Tony Chan

367
Non riesci a credere ai 64 voti positivi? Quel codice ovviamente funziona solo se èd già un , nel qual caso è banale recuperarlo come bitmap ... Si bloccherà in tutti gli altri casi. BitmapDrawableClassCastException
Matthias,

3
@Matthias per non parlare del fatto che .. la domanda stessa, stesso autore, ha 100 voti: /
quinestor il

2
Questo è così specializzato in un caso banale.
njzk2,

141

A Drawablepuò essere disegnato su a Canvase a Canvaspuò essere supportato da a Bitmap:

(Aggiornato per gestire una conversione rapida per BitmapDrawables e per garantire che il Bitmapcreato abbia una dimensione valida)

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

Cosa succede se il parametro drawable è null?
hrules6872,

1
Questo metodo non supporta VectorDrawable
Mahmoud


Supponendo di ottenere un Drawable non vuoto, perché è necessario verificare che larghezza e altezza non siano 0? Inoltre, perché è necessario utilizzare setBounds () se hanno le stesse dimensioni?
Yoav Feuerstein,

Buona soluzione! Android 8.0 / sdk 26 ApplicationInfo.loadIcon (PackageManager pm) restituisce un AdaptiveIconDrawable。 Usa il tuo codice può aiutarmi a lanciare AdaptiveIconDrawable in bitmap。
burulangtu,

43

METODO 1 : O è possibile convertire direttamente in bitmap in questo modo

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

METODO 2 : puoi persino convertire la risorsa in un disegno e da questo puoi ottenere bitmap in questo modo

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

Per API> 22 il getDrawable metodo è stato spostato nella ResourcesCompatclasse in modo da fare qualcosa del genere

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

ResourcesCompat funziona solo se il disegno è un BitmapDrawable, se stai usando VectorDrawable, allora avrai un CCE.
Brill Pappin,

Nessuno di questi funziona con una risorsa VectorDrawable . Si verifica il seguente errore:android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz,

Questa soluzione funziona bene con Kotlin.
Adam Hurwitz,


15

Quindi, dopo aver guardato (e usato) le altre risposte, sembrano gestirle tutte ColorDrawablee PaintDrawablemale. (Soprattutto sul lecca-lecca) sembrava che Shaderfossero stati modificati i solidi blocchi di colori non gestiti correttamente.

Sto usando il seguente codice ora:

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

A differenza degli altri, se chiami setBounds sulla Drawableprima di chiedere per trasformarlo in una bitmap, si disegnerà la bitmap con le dimensioni corrette!


SetBounds non rovinerebbe i limiti precedenti del drawable? Non è meglio archiviarlo e ripristinarlo in seguito?
sviluppatore Android l'

@androiddeveloper, se i limiti sono stati fissati, li stiamo usando comunque. In alcuni casi questo è necessario dove non sono stati impostati limiti e non ha dimensioni intrinseche (come ColorDrawables in alcuni casi). Quindi la larghezza e l'altezza sarebbero 0, diamo il 1x1 disegnabile in quel modo in cui effettivamente disegna qualcosa. Potrei sostenere che potremmo fare un controllo del tipo per ColorDrawable in quei casi, ma questo funziona per il 99% dei casi. (Puoi modificarlo per le tue esigenze).
Chris.Jenkins,

@ Chris.Jenkins E se non avesse limiti, e ora ne avranno di nuovi? Vorrei anche porre un'altra domanda: qual è il modo migliore per impostare la dimensione della bitmap (anche per BitmapDrawable) che viene restituita?
sviluppatore Android l'

Ti consiglio di leggere attentamente il codice. Se il Drawablenon ha limiti impostati, utilizza il IntrinsicWidth/Height. Se sono entrambi <= 0 impostiamo il canvas su 1px. Hai ragione se Drawablenon ha limiti verrà superato alcuni (1x1 è nella maggior parte dei casi), ma questo è NECESSARIO per cose come quelle ColorDrawableche NON hanno dimensioni intrinseche. Se non lo facessimo, verrebbe lanciato un Exception, non puoi disegnare 0x0 su una tela.
Chris.Jenkins,

1
mutate()farebbe una copia lasciando solo il disegno originale che negherebbe il problema di tornare indietro nei limiti originali. Raramente cambio codice in base a questi punti. Se il tuo caso d'uso lo richiede, aggiungi un'altra risposta. Ti suggerisco di creare un'altra domanda per il ridimensionamento Bitmap.
Chris.Jenkins,

13

Forse questo aiuterà qualcuno ...

Da PictureDrawable a Bitmap, utilizzare:

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

... implementato come tale:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);

Come per la risposta di Rob, hai bisogno di un tipo specifico di Drawable, in questo caso a PictureDrawable.
Kabuko,

4
"Forse questo aiuterà qualcuno ..."
Mauro,

11

Ecco una migliore risoluzione

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

Codice da Come leggere i bit disegnabili come InputStream


11

1) disegnabile su Bitmap:

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

2) bitmap a Drawable:

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

10

Ecco la bella versione di Kotlin della risposta fornita da @ Chris.Jenkins qui: 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 fornisce una soluzione non dritto in avanti: BitmapDrawable. Per ottenere la Bitmap, dovremo fornire l'ID risorsa R.drawable.flower_pica a BitmapDrawablee quindi trasmetterlo a Bitmap.

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

5

Usa questo codice.it ti aiuterà a raggiungere il tuo obiettivo.

 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()ridimensiona automaticamente la bitmap, quindi la bitmap potrebbe risultare sfocata. Per evitare il ridimensionamento, procedere come segue:

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

o

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

2

se stai usando kotlin, usa il codice qui sotto. funzionerà

// per l'utilizzo del percorso dell'immagine

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

Penso che tu abbia letto la domanda in modo sbagliato. La domanda si pone: come ottenere una bitmap da una risorsa
estraibile

1

La libreria ImageWorker può convertire bitmap in drawable o base64 e viceversa.

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

Implementazione

In Grado a livello di progetto

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

In Grado a livello di applicazione

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

È inoltre possibile memorizzare e recuperare bitmap / disegni / immagini base64 da esterni.

Controlla qui https://github.com/1AboveAll/ImageWorker/edit/master/README.md

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.