¿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.



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

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

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

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

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

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


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!


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

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


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

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


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

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

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

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


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

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.