Bitmap do Android para String Base64

128

Como converter um Bitmap grande (foto tirada com a câmera do telefone) em uma String Base64?

Pankaj Singh
fonte
Como você deseja codificar a imagem?
Ted Hopp
Você está fazendo a pergunta errada. As fotos tiradas com a câmera do telefone são armazenadas como JPEG, não como bitmaps. Você só precisa decodificar o jpeg em um bitmap com a finalidade de exibi-lo. Você terá menos erros OutOfMemory e processamento desnecessário se seguir minha resposta abaixo.
Carson Holzheimer

Respostas:

301

use o seguinte método para converter bitmap em matriz de bytes:

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

para codificar base64 a partir da matriz de bytes, use o seguinte método

String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
jeet
fonte
Obrigado pela solução, eu usei o mesmo código, mas minha string codificada tem ... no final e acho que não é convertida completamente, por favor, diga-me por que no final da string Base 64 estão os pontos (...) ..
Pankaj Singh
@Pankaj Oi u pode me dizer como u resolver essa questão, im enfrentando mesmo problema na minha string codificada tem 3 pontos (...) pode u por favor me ajude a resolver isso
Sachin Gurnani
5
@SachinGurnani - mostra ... porque o logcat mostra um número limitado de String e depois disso é truncado. é por isso.
Pankaj Singh
Obrigado pela sua resposta Pankaj. i teve sove este problema no mesmo dia em si
Sachin Gurnani
1
isso deve ser feito no asynctask? ou é bom fazer isso no thread principal?
N3wb
28

Eu tenho solução rápida. Basta criar um arquivoImageUtil.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);

ou

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

O problema com a resposta de jeet é que você carrega todos os bytes da imagem em uma matriz de bytes, o que provavelmente trava o aplicativo em dispositivos low-end. Em vez disso, primeiro eu escrevia a imagem em um arquivo e a lia usando a classe Base64InputStream do Apache . Em seguida, você pode criar a string Base64 diretamente do InputStream desse arquivo. Isso parecerá assim:

//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 você pode ver, a solução acima trabalha diretamente com fluxos, evitando a necessidade de carregar todos os bytes em uma variável, tornando a área de memória muito menor e com menor probabilidade de travar em dispositivos low-end. Ainda existe o problema de colocar a própria seqüência Base64 em uma variável String não é uma boa ideia, pois, novamente, isso pode causar erros OutOfMemory. Mas pelo menos reduzimos pela metade o consumo de memória, eliminando a matriz de bytes.

Se você quiser pular a etapa de gravação em um arquivo, precisará converter o OutputStream em um InputStream, o que não é tão simples de fazer (você deve usar o PipedInputStream, mas isso é um pouco mais complexo, pois os dois fluxos sempre devem estar em segmentos diferentes).

Tiago
fonte
2
O que é codificação aqui?
Animesh Mangla
5

Tente isso, primeiro redimensione sua imagem para a largura e a altura necessárias, basta passar o bitmap original, a largura e a altura necessárias para o método a seguir e obter o bitmap em escala em troca:

Por exemplo: 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);
}

Agora basta passar seu bitmap escalado para o seguinte método e obter a sequência base64 em troca:

Por exemplo: 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 a sequência base64 de volta à imagem de bitmap:

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

Todas essas respostas são ineficientes, pois decodificam desnecessariamente um bitmap e, em seguida, recomprima o bitmap. Quando você tira uma foto no Android, ela é armazenada como um JPEG no arquivo temporário especificado quando você segue os documentos do Android .

O que você deve fazer é converter diretamente esse arquivo em uma string Base64. Aqui está como fazer isso em cópia-colar fácil (em Kotlin). Observe que você deve fechar o base64FilterStream para realmente liberar seu buffer 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 um bônus, sua qualidade de imagem deve ser ligeiramente melhorada, devido ao desvio da recompactação.

Carson Holzheimer
fonte
1

Agora que a maioria das pessoas usa o Kotlin em vez de Java, eis o código no Kotlin para converter um bitmap em uma string 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
fonte
-2

Use 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);
    }
}
Acme Developers
fonte