¿Cómo convertir un Drawable a un mapa de bits?

949

Me gustaría establecer un determinado Drawablecomo fondo de pantalla del dispositivo, pero todas las funciones de fondo de pantalla Bitmapsolo aceptan s. No puedo usar WallpaperManagerporque soy pre 2.1.

Además, mis dibujos se descargan de la web y no residen en ellos R.drawable.

Robar
fuente
1
elija la respuesta correcta, esto: stackoverflow.com/a/3035869/4548520
user25

Respuestas:

1290

Este fragmento de código ayuda.

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

Aquí una versión donde se descarga la imagen.

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);
}
Praveen
fuente
1
Creo que tienes los valores de URL. entonces mi respuesta editada debería ayudar.
Praveen
de donde viene str_url? No pude encontrar ninguna función Drawable relacionada con las cadenas ... gracias por su ayuda.
Rob
12
Creo que encontré algo: si "dibujar" es el dibujo que quiero convertir en un mapa de bits, entonces: Mapa de bits mapa de bits = ((BitmapDrawable) draw) .getBitmap (); ¡Hace el truco!
Rob
1
@Rob: si su Drawable es un BitmapDrawable solamente. (lo que significa que su Drawable no es más que una envoltura alrededor de un mapa de bits, en realidad)
njzk2
2
nota: esto causa un java.lang.OutOfMemoryError masivo 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;
}
André
fuente
41
Esta parece ser la única respuesta que funcionaría para cualquier tipo de dibujo y también tiene una solución rápida para un dibujo que ya es un BitmapDrawable. +1
Matt Wolfe
1
solo una enmienda: docs dice acerca de BitmapDrawable.getBitmap () que puede volverse nulo. Yo digo que también puede volver ya reciclado.
Kellogs
16
Cuidado: getIntrinsicWidth()y getIntrinsicHieght()devolverá -1 si dibujable es un color sólido.
SD
55
Entonces ... otro cheque para ColorDrawable, y tenemos un ganador. En serio, alguien haga de esta la respuesta aceptada.
kaay
2
Contrariamente a la respuesta marcada, esto responde a la pregunta.
njzk2
214

Esto convierte un BitmapDrawable en un Bitmap.

Drawable d = ImagesArrayList.get(0);  
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();
Robar
fuente
99
¿Es esta realmente la mejor manera? Seguramente el sorteo podría ser de otro tipo y esto generaría una excepción de tiempo de ejecución. Por ejemplo, podría ser un ninePatchDrawble ...?
Dori
44
@Dori, podría envolver el código en una declaración condicional para verificar si realmente es un BitmapDrawableantes de lanzarlo: if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Tony Chan
367
¿No puedo creer los 64 votos a favor? Obviamente, ese código solo funciona si dya es un BitmapDrawable, en cuyo caso es trivial recuperarlo como un mapa de bits ... Se bloqueará ClassCastExceptionen todos los demás casos.
Matthias el
3
@Matthias sin mencionar que ... la pregunta en sí, el mismo autor, tiene 100 votos: /
quinestor
2
Esto está tan especializado en un caso trivial.
njzk2
141

A Drawablese puede dibujar sobre a Canvas, y a Canvaspuede ser respaldado por Bitmap:

(Actualizado para manejar una conversión rápida para BitmapDrawablesy para garantizar que lo Bitmapcreado tenga un tamaño 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;
}
kabuko
fuente
¿Qué sucede si el parámetro dibujable es nulo?
hrules6872
1
Este método no es compatible con VectorDrawable
Mahmoud
Suponiendo que obtiene un Drawable no vacío, ¿por qué es necesario verificar que el ancho y la altura no sean 0? Además, ¿por qué necesita usar setBounds () si son del mismo tamaño?
Yoav Feuerstein
Buena solución! Android 8.0 / sdk 26 ApplicationInfo.loadIcon (PackageManager pm) devuelve un AdaptiveIconDrawable。 Usar su código puede ayudarme a
transmitir
43

MÉTODO 1 : puede convertir directamente a mapa de bits como este

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

MÉTODO 2 : Incluso puede convertir el recurso en dibujable y de eso puede obtener un mapa de bits como este

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

Para API> 22, el getDrawable método se movió a la ResourcesCompatclase, por lo que debe hacer algo como esto

Bitmap myLogo = ((BitmapDrawable) ResourcesCompat.getDrawable(context.getResources(), R.drawable.logo, null)).getBitmap();
Keyur
fuente
ResourcesCompat solo funciona si el dibujable es un BitmapDrawable, si está utilizando VectorDrawable, entonces tendrá un CCE.
Brill Pappin
Ninguno de estos funciona con un recurso VectorDrawable . Se produce el siguiente error:android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz
Esta solución funciona bien con Kotlin.
Adam Hurwitz
31

muy simple

Bitmap tempBMP = BitmapFactory.decodeResource(getResources(),R.drawable.image);
Erfan Bagheri
fuente
66
Esto es solo el plagio de la otra respuesta a esta pregunta tres años antes
Nick Cardoso
15

Así que después de mirar (y usar) de las otras respuestas, parece que todo el manejo ColorDrawabley el PaintDrawablemal. (Especialmente en lollipop) parecía que se Shaderhabían ajustado los s para que los bloques sólidos de colores no se manejaran correctamente.

Estoy usando el siguiente código ahora:

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 diferencia de los demás, si se llama setBoundsa la Drawableantes de pedir para convertirlo en un mapa de bits, se dibujará el mapa de bits en el tamaño correcto!

Chris Jenkins
fuente
¿SetBounds no arruinaría los límites anteriores del sorteo? ¿No es mejor almacenarlo y restaurarlo después?
Desarrollador de Android
@androiddeveloper, si se han establecido los límites, los estamos usando de todos modos. En algunos casos, esto es necesario cuando no se han establecido límites y no tiene un tamaño intrínseco (como ColorDrawables en algunos casos). Entonces, el ancho y la altura serían 0, le damos al 1x1 dibujable de esa manera que realmente dibuja algo. Podría argumentarse que podríamos hacer una verificación de tipo para ColorDrawable en esos casos, pero esto funciona para el 99% de los casos. (Puede modificarlo según sus necesidades).
Chris.Jenkins
@ Chris.Jenkins ¿Qué pasa si no tiene límites y ahora obtendrá otros nuevos? También me gustaría hacer otra pregunta: ¿cuál es la mejor manera de establecer el tamaño del mapa de bits (incluso para BitmapDrawable) que se devuelve?
Desarrollador de Android
Te sugiero que leas cuidadosamente el código. Si el Drawableno tiene límites establecidos, usa el IntrinsicWidth/Height. Si ambos son <= 0, establecemos el lienzo en 1px. Estás en lo correcto si Drawableno tiene límites, se pasará un poco (1x1 es la mayoría de los casos), pero esto se REQUIERE para cosas como las ColorDrawableque NO tienen tamaños intrínsecos. Si no hiciéramos esto, arrojaría un Exception, no puedes dibujar 0x0 en un lienzo.
Chris.Jenkins
1
mutate()haría una copia dejando solo el dibujo original, lo que negaría el problema de pasar de nuevo a los límites originales. Raramente cambio el código basado en esos puntos. Si su caso de uso lo requiere, agregue otra respuesta. Le sugiero que cree otra pregunta para la escala de mapa de bits.
Chris.Jenkins
13

Quizás esto ayude a alguien ...

Desde PictureDrawable a 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);
Mauro
fuente
Al igual que con la respuesta de Rob, necesita un tipo específico de Drawable, en este caso, a PictureDrawable.
kabuko
44
"Quizás esto ayude a alguien ..."
Mauro
11

Aquí hay una mejor resolución

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 Cómo leer bits dibujables como InputStream

Dawid Drozd
fuente
11

1) dibujable a Bitmap:

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

2) mapa de bits a Drawable:

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

Aquí está la buena versión de Kotlin de la respuesta proporcionada por @ Chris.Jenkins aquí: 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
tasomaníaco
fuente
8

Android proporciona una solución foward no lineal: BitmapDrawable. Para obtener el mapa de bits, tendremos que proporcionar la identificación del recurso R.drawable.flower_pica la BitmapDrawabley luego convertirla en a Bitmap.

Bitmap bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.flower_pic)).getBitmap();
kc ochibili
fuente
5

Use este código. Le ayudará a lograr su 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;
}
Anupam Sharma
fuente
3

BitmapFactory.decodeResource()escala automáticamente el mapa de bits, por lo que su mapa de bits puede aparecer borroso. Para evitar el escalado, haga esto:

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);
John Doe
fuente
2

si está usando kotlin, use el siguiente código. funcionará

// para usar la ruta de la imagen

val image = Drawable.createFromPath(path)
val bitmap = (image as BitmapDrawable).bitmap
Sachidananda Sahu
fuente
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);
        }
    }
}
Ángel
fuente
Creo que leíste mal la pregunta. La pregunta es: cómo obtener un mapa de bits de un recurso extraíble, no de la galería del sistema
kc ochibili
1

ImageWorker Library puede convertir mapas de bits a dibujables o base64 y viceversa.

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

Implementación

En Project Level Gradle

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

En el nivel de aplicación Gradle

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

También puede almacenar y recuperar imágenes de mapas de bits / dibujables / base64 desde el exterior.

Chequea aquí. https://github.com/1AboveAll/ImageWorker/edit/master/README.md

Himanshu Rawat
fuente