Como converter um Drawable em um Bitmap?


948

Gostaria de definir um certo Drawablepapel de parede do dispositivo, mas todas as funções do papel de parede aceitam Bitmapapenas s. Não posso usar WallpaperManagerporque sou pré-2.1.

Além disso, meus drawables são baixados da Web e não residem R.drawable.



1
Por favor, escolha a resposta certa: stackoverflow.com/a/3035869/4548520
user25

Respostas:


1289

Este pedaço de código ajuda.

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

Aqui está uma versão em que a imagem é baixada.

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
Eu acho que você tem os valores de URL. então minha resposta editada deve ajudar.
Praveen

de onde vem str_url? Não consegui encontrar nenhuma função Drawable relacionada a strings ... obrigado pela sua ajuda.
Rob

12
Eu acho que encontrei algo: se "draw" é o drawable que eu quero converter em um bitmap, então: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); faz o truque!
Rob

1
@ Rob: se o seu Drawable é apenas um BitmapDrawable. (o que significa que o seu Drawable é apenas um invólucro em torno de um Bitmap, na verdade)
njzk2

2
note: isso causa java.lang.OutOfMemoryError com 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
Parece a única resposta que funcionaria para qualquer tipo de drawable e também possui uma solução rápida para um drawable que já é um BitmapDrawable. 1
Matt Wolfe

1
apenas uma alteração: a docs diz sobre o BitmapDrawable.getBitmap () que ele pode voltar nulo. Eu digo que também pode voltar já reciclado.
Kellogs

16
Cuidado: getIntrinsicWidth()e getIntrinsicHieght()retornará -1 se o drawable for uma cor sólida.
SD

5
Então ... outra verificação para ColorDrawable, e nós temos um vencedor. Sério, alguém faz disso a resposta aceita.
Kaay

2
Ao contrário da resposta sinalizada, isso responde à pergunta.
Njzk2 28/05

214

Isso converte um BitmapDrawable em um Bitmap.

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

9
este é realmente o melhor caminho? Certamente o drawable poderia ser de outro tipo e isso geraria uma runtimeException? Por exemplo, poderia ser um ninePatchDrawble ...?
Dori

4
@Dori você poderia envolver o código em uma instrução condicional para verificar se ele é realmente um BitmapDrawableantes de convertê-lo: if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Tony Chan

367
Não posso acreditar nos 64 votos positivos? Obviamente, esse código só funciona se dfor um BitmapDrawable; nesse caso, é trivial recuperá-lo como um bitmap ... Irá falhar ClassCastExceptionem todos os outros casos.
Matthias

3
@ Matthias para não mencionar que .. a pergunta em si, mesmo autor, tem 100 votos: /
quinestor

2
Isso é tão especializado em um caso trivial.
Njzk2 28/05

141

A Drawablepode ser desenhado em um Canvase a Canvaspode ser apoiado por um Bitmap:

(Atualizado para lidar com uma conversão rápida de BitmapDrawablese garantir que o Bitmapcriado tenha um tamanho válido)

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

O que acontece se o parâmetro drawable for nulo?
Hrules6872

1
Este método não suporta VectorDrawable
Mahmoud


Supondo que você obtenha um Drawable não vazio, por que é necessário verificar se a largura e a altura não são 0? Além disso, por que você precisa usar setBounds () se eles são do mesmo tamanho?
Yoav Feuerstein 30/01

!. Boa solução Android 8.0 / SDK 26 ApplicationInfo.loadIcon (PackageManager pm) retornar um AdaptiveIconDrawable Use seu código pode me ajudar a lançar AdaptiveIconDrawable para bitmap.
burulangtu

43

MÉTODO 1 : Você pode converter diretamente em bitmap como este

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

MÉTODO 2 : Você pode até converter o recurso no drawable e, a partir disso, obter um bitmap como este

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

Para o método API> 22 getDrawable movido para a ResourcesCompatclasse, é necessário fazer algo assim

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

ResourcesCompat funciona apenas se o drawable for um BitmapDrawable; se você estiver usando VectorDrawable, terá um CCE.
Brill Pappin

Nenhum deles funciona com um recurso VectorDrawable . O seguinte erro ocorre -android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz

Esta solução funciona bem com o Kotlin.
Adam Hurwitz


15

Então, depois de procurar (e usar) as outras respostas, parece que todas estão lidando mal ColorDrawablee PaintDrawablemal. (Especialmente no pirulito) parecia que Shaders eram ajustados para que blocos de cores sólidos não fossem manuseados corretamente.

Estou usando o seguinte código agora:

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

Diferente dos outros, se você solicitar setBoundso Drawableantes de transformá-lo em um bitmap, ele desenhará o bitmap no tamanho correto!


O setBounds não arruinaria os limites anteriores do drawable? Não é melhor armazená-lo e restaurá-lo depois?
desenvolvedor android

@androiddeveloper, se os limites foram definidos, estamos usando esses de qualquer maneira. Em alguns casos, isso é necessário quando nenhum limite foi definido e não possui tamanho intrínseco (como o ColorDrawables em alguns casos). Portanto, largura e altura seriam 0, damos o drawable 1x1 dessa maneira que ele realmente desenha alguma coisa. Posso argumentar que poderíamos fazer uma verificação de tipo para ColorDrawable nesses casos, mas isso funciona para 99% dos casos. (Você pode modificá-lo para suas necessidades).
Chris.Jenkins

@ Chris.Jenkins E se ele não tiver limites, e agora terá novos? Gostaria também de fazer outra pergunta: qual é a melhor maneira de definir o tamanho do bitmap (mesmo para o BitmapDrawable) que é retornado?
android developer

Eu sugiro que você leia atentamente o código. Se o Drawablenão tiver limites definidos, ele usa o IntrinsicWidth/Height. Se ambos forem <= 0, configuramos a tela como 1px. Você está correto se o Drawablenão tiver limites, será passado alguns (1x1 é a maioria dos casos), mas isso é NECESSÁRIO para coisas como as ColorDrawableque NÃO possuem tamanhos intrínsecos. Se não fizéssemos isso, lançaria um Exception, você não pode desenhar 0x0 em uma tela.
Chris.Jenkins

1
mutate()faria uma cópia deixando o drawable original sozinho, o que negaria a questão de retornar aos limites originais. Raramente altero o código com base nesses pontos. Se o seu caso de uso exigir, adicione outra resposta. Sugiro que você crie outra pergunta para o dimensionamento de bitmap.
precisa saber é o seguinte

13

Talvez isso ajude alguém ...

De PictureDrawable para Bitmap, use:

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

... implementado como tal:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);

Como na resposta de Rob, você está exigindo um tipo específico de Drawable, neste caso a PictureDrawable.
kabuko

4
"Talvez isso ajude alguém ..."
Mauro

11

Aqui está melhor resolução

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

Código de Como ler bits desenháveis ​​como InputStream


11

1) extraível para Bitmap:

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

2) bitmap para Drawable:

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

10

Aqui está a boa versão do Kotlin da resposta fornecida por @ Chris.Jenkins aqui: 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 fornece uma solução para a frente não direto: BitmapDrawable. Para obter o Bitmap, precisaremos fornecer o ID do recurso R.drawable.flower_picpara a BitmapDrawablee depois convertê-lo em a Bitmap.

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

5

Use este code.it irá ajudá-lo a alcançar seu objetivo.

 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()dimensiona automaticamente o bitmap, para que seu bitmap fique confuso. Para impedir o dimensionamento, faça o seguinte:

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

Se você estiver usando o kotlin, use o código abaixo. vai funcionar

// para usar o caminho da imagem

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

Eu acho que você leu a pergunta errado. A pergunta é: como obter um bitmap de um recurso drawable não galeria sistema
kc ochibili

1

A Biblioteca ImageWorker pode converter bitmap em drawable ou base64 e vice-versa.

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

Implementação

No nível do projeto Gradle

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

No nível do aplicativo Gradle

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

Você também pode armazenar e recuperar imagens de bitmaps / drawables / base64 de fora.

Verifique aqui. https://github.com/1AboveAll/ImageWorker/edit/master/README.md

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.