Mapa de bits de Android a cadena Base64

128

¿Cómo convierto un mapa de bits grande (foto tomada con la cámara del teléfono) en una cadena Base64?

Pankaj Singh
fuente
¿Cómo quieres codificar la imagen?
Ted Hopp
Estás haciendo la pregunta equivocada. Las fotos tomadas con la cámara del teléfono se almacenan como JPEG, no como mapas de bits. Solo necesita decodificar el jpeg en un mapa de bits con el fin de mostrarlo. Tendrá menos errores de OutOfMemory y procesamiento innecesario si sigue mi respuesta a continuación.
Carson Holzheimer

Respuestas:

301

use el siguiente método para convertir el mapa de bits en una matriz de bytes:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();  
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();

para codificar base64 desde la matriz de bytes, utilice el siguiente método

String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
jeet
fuente
Gracias por la solución, he usado el mismo código pero mi cadena codificada tiene ... al final y creo que no se ha convertido completamente, así que por favor díganme por qué al final de la cadena Base 64 están los puntos (...) ..
Pankaj Singh
@Pankaj Hola, ¿puedes decirme cómo resuelves ese problema? Estoy enfrentando el mismo problema en mi cadena codificada que tiene 3 puntos (...) ¿Puedes ayudarme a resolver eso?
Sachin Gurnani
55
@SachinGurnani: se muestra ... porque el logcat muestra una longitud de cadena limitada y luego se trunca. es por eso.
Pankaj Singh
Gracias por tu respuesta Pankaj. Había resuelto este problema el mismo día mismo
Sachin Gurnani
1
¿Debería hacerse esto en asinctask? ¿o está bien hacer esto en el hilo principal?
n3wb
28

Tengo una solución rápida Solo crea un archivoImageUtil.java

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import java.io.ByteArrayOutputStream;

public class ImageUtil
{
    public static Bitmap convert(String base64Str) throws IllegalArgumentException
    {
        byte[] decodedBytes = Base64.decode(
            base64Str.substring(base64Str.indexOf(",")  + 1),
            Base64.DEFAULT
        );

        return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
    }

    public static String convert(Bitmap bitmap)
    {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);

        return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
    }

}

Uso:

Bitmap bitmap = ImageUtil.convert(base64String);

o

String base64String = ImageUtil.convert(bitmap);
Vasilii Suricov
fuente
13

El problema con la respuesta de jeet es que carga todos los bytes de la imagen en una matriz de bytes, lo que probablemente bloqueará la aplicación en dispositivos de gama baja. En cambio, primero escribiría la imagen en un archivo y la leería usando la clase Base64InputStream de Apache . Luego puede crear la cadena Base64 directamente desde InputStream de ese archivo. Se verá así:

//Don't forget the manifest permission to write files
final FileOutputStream fos = new FileOutputStream(yourFileHere); 
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);

fos.close();

final InputStream is = new Base64InputStream( new FileInputStream(yourFileHere) );

//Now that we have the InputStream, we can read it and put it into the String
final StringWriter writer = new StringWriter();
IOUtils.copy(is , writer, encoding);
final String yourBase64String = writer.toString();

Como puede ver, la solución anterior funciona directamente con secuencias, evitando la necesidad de cargar todos los bytes en una variable, por lo tanto, la huella de memoria es mucho menor y es menos probable que se bloquee en dispositivos de gama baja. Todavía existe el problema de que colocar la cadena Base64 en una variable de cadena no es una buena idea, porque, nuevamente, puede causar errores de OutOfMemory. Pero al menos hemos reducido el consumo de memoria a la mitad al eliminar la matriz de bytes.

Si desea omitir el paso de escribir en un archivo, debe convertir el OutputStream en un InputStream, que no es tan sencillo de hacer (debe usar PipedInputStream pero eso es un poco más complejo ya que los dos flujos siempre deben estar en diferentes hilos).

Tiago
fuente
2
¿Qué es la codificación aquí?
Animesh Mangla
5

Pruebe esto, primero escale su imagen al ancho y la altura requeridos, simplemente pase su mapa de bits original, el ancho requerido y la altura requerida al siguiente método y obtenga un mapa de bits escalado a cambio:

Por ejemplo: Bitmap scaledBitmap = getScaledBitmap (originalBitmap, 250, 350);

private Bitmap getScaledBitmap(Bitmap b, int reqWidth, int reqHeight)
{
    int bWidth = b.getWidth();
    int bHeight = b.getHeight();

    int nWidth = bWidth;
    int nHeight = bHeight;

    if(nWidth > reqWidth)
    {
        int ratio = bWidth / reqWidth;
        if(ratio > 0)
        {
            nWidth = reqWidth;
            nHeight = bHeight / ratio;
        }
    }

    if(nHeight > reqHeight)
    {
        int ratio = bHeight / reqHeight;
        if(ratio > 0)
        {
            nHeight = reqHeight;
            nWidth = bWidth / ratio;
        }
    }

    return Bitmap.createScaledBitmap(b, nWidth, nHeight, true);
}

Ahora simplemente pase su mapa de bits escalado al siguiente método y obtenga una cadena base64 a cambio:

Por ejemplo: String base64String = getBase64String (scaledBitmap);

private String getBase64String(Bitmap bitmap)
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

    byte[] imageBytes = baos.toByteArray();

    String base64String = Base64.encodeToString(imageBytes, Base64.NO_WRAP);

    return base64String;
}

Para decodificar la cadena base64 de nuevo a la imagen de mapa de bits:

byte[] decodedByteArray = Base64.decode(base64String, Base64.NO_WRAP);
Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decodedByteArray, 0, decodedString.length);
Ashwin
fuente
3

Todas estas respuestas son ineficientes ya que decodifican innecesariamente un mapa de bits y luego vuelven a comprimir el mapa de bits. Cuando toma una foto en Android, se almacena como un archivo JPEG en el archivo temporal que especifica cuando sigue los documentos de Android .

Lo que debe hacer es convertir directamente ese archivo a una cadena Base64. Aquí se explica cómo hacerlo fácilmente en copiar y pegar (en Kotlin). Tenga en cuenta que debe cerrar el base64FilterStream para vaciar realmente su búfer interno.

fun convertImageFileToBase64(imageFile: File): String {

    return FileInputStream(imageFile).use { inputStream ->
        ByteArrayOutputStream().use { outputStream ->
            Base64OutputStream(outputStream, Base64.DEFAULT).use { base64FilterStream ->
                inputStream.copyTo(base64FilterStream)
                base64FilterStream.close()
                outputStream.toString()
            }
        }
    }
}

Como beneficio adicional, la calidad de su imagen debería mejorarse ligeramente, sin pasar por la compresión.

Carson Holzheimer
fuente
1

Ahora que la mayoría de la gente usa Kotlin en lugar de Java, aquí está el código en Kotlin para convertir un mapa de bits en una cadena base64.

import java.io.ByteArrayOutputStream

private fun encodeImage(bm: Bitmap): String? {
        val baos = ByteArrayOutputStream()
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val b = baos.toByteArray()
        return Base64.encodeToString(b, Base64.DEFAULT)
    }
Reddy Tintaya
fuente
-2

Usa este código ...

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import java.io.ByteArrayOutputStream;

public class ImageUtil 
{ 
    public static Bitmap convert(String base64Str) throws IllegalArgumentException 
    { 
        byte[] decodedBytes = Base64.decode( base64Str.substring(base64Str.indexOf(",") + 1), Base64.DEFAULT );
        return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
    } 

    public static String convert(Bitmap bitmap) 
    { 
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
    }
}
Desarrolladores Acme
fuente