Mapa bitowa systemu Android na ciąg Base64

128

Jak przekonwertować dużą mapę bitową (zdjęcie zrobione aparatem telefonu) na ciąg Base64?

Pankaj Singh
źródło
Jak chcesz zakodować obraz?
Ted Hopp,
Zadajesz złe pytanie. Zdjęcia zrobione aparatem telefonu są zapisywane jako jpeg, a nie bitmapy. Wystarczy zdekodować jpeg do mapy bitowej w celu jej wyświetlenia. Będziesz mieć mniej błędów OutOfMemory i niepotrzebnego przetwarzania, jeśli zastosujesz się do mojej odpowiedzi poniżej.
Carson Holzheimer,

Odpowiedzi:

301

użyj następującej metody, aby przekonwertować bitmapę na tablicę bajtów:

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

aby zakodować base64 z tablicy bajtów, użyj następującej metody

String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
jeet
źródło
Dzięki za rozwiązanie, użyłem tego samego kodu, ale mój zakodowany ciąg ma ... na końcu i myślę, że nie jest całkowicie przekonwertowany, więc proszę mi powiedzieć, dlaczego na końcu ciągu Base 64 są kropki (...) ..
Pankaj Singh,
@Pankaj Cześć, czy możesz mi powiedzieć, jak rozwiązujesz ten problem, mam ten sam problem w moim zakodowanym ciągu ma 3 kropki (...) czy możesz pomóc, proszę, pomóc go rozwiązać
Sachin Gurnani
5
@SachinGurnani - pokazuje ... ponieważ logcat pokazuje ograniczoną długość łańcucha, a następnie jest obcięty. dlatego.
Pankaj Singh
Dzięki za Twoją odpowiedź Pankaj. rozwiązałem ten problem tego samego dnia
Sachin Gurnani,
1
należy to zrobić w asynctask? czy można to zrobić w głównym wątku?
n3wb
28

Mam szybkie rozwiązanie. Po prostu utwórz plikImageUtil.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);
    }

}

Stosowanie:

Bitmap bitmap = ImageUtil.convert(base64String);

lub

String base64String = ImageUtil.convert(bitmap);
Vasilii Suricov
źródło
13

Problem z odpowiedzią jeeta polega na tym, że ładujesz wszystkie bajty obrazu do tablicy bajtów, co prawdopodobnie spowoduje awarię aplikacji na urządzeniach z niższej półki. Zamiast tego najpierw zapisałbym obraz do pliku i odczytał go za pomocą klasy Base64InputStream Apache . Następnie możesz utworzyć ciąg Base64 bezpośrednio z InputStream tego pliku. Będzie to wyglądać tak:

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

Jak widać, powyższe rozwiązanie działa bezpośrednio ze strumieniami zamiast tego, unikając konieczności ładowania wszystkich bajtów do zmiennej, dzięki czemu zużycie pamięci jest znacznie mniejsze i mniej prawdopodobne jest awarie w urządzeniach o niższej jakości. Nadal istnieje problem polegający na tym, że umieszczenie samego ciągu Base64 w zmiennej String nie jest dobrym pomysłem, ponieważ znowu może powodować błędy OutOfMemory. Ale przynajmniej zmniejszyliśmy zużycie pamięci o połowę, eliminując tablicę bajtów.

Jeśli chcesz pominąć krok zapisu do pliku, musisz przekonwertować OutputStream na InputStream, co nie jest takie proste (musisz użyć PipedInputStream, ale jest to trochę bardziej złożone, ponieważ dwa strumienie muszą zawsze być w różnych wątkach).

Tiago
źródło
2
Co tu jest kodowanie?
Animesh Mangla,
5

Spróbuj tego, najpierw przeskaluj obraz do wymaganej szerokości i wysokości, po prostu przekaż oryginalną bitmapę, wymaganą szerokość i wymaganą wysokość do następującej metody i otrzymaj w zamian skalowaną bitmapę:

Na przykład: 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);
}

Teraz po prostu przekaż skalowaną bitmapę do następującej metody i otrzymaj w zamian ciąg base64:

Na przykład: 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;
}

Aby zdekodować ciąg base64 z powrotem do obrazu bitmapowego:

byte[] decodedByteArray = Base64.decode(base64String, Base64.NO_WRAP);
Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decodedByteArray, 0, decodedString.length);
Ashwin
źródło
3

Wszystkie te odpowiedzi są nieefektywne, ponieważ niepotrzebnie dekodują do mapy bitowej, a następnie ponownie ją kompresują. Kiedy robisz zdjęcie w systemie Android, jest ono przechowywane jako jpeg w pliku tymczasowym, który określasz podczas śledzenia dokumentów systemu Android .

To, co powinieneś zrobić, to bezpośrednio przekonwertować ten plik na ciąg Base64. Oto jak to zrobić w łatwym kopiowaniu i wklejaniu (w Kotlinie). Zauważ, że musisz zamknąć base64FilterStream, aby naprawdę opróżnić jego wewnętrzny bufor.

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

Jako bonus, jakość obrazu powinna zostać nieznacznie poprawiona dzięki pominięciu ponownej kompresji.

Carson Holzheimer
źródło
1

Teraz, gdy większość ludzi używa Kotlin zamiast Javy, oto kod w Kotlinie do konwersji mapy bitowej na ciąg 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
źródło
-2

Użyj tego kodu ..

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
źródło