Konvertieren der Java-Bitmap in ein Byte-Array

292
  Bitmap bmp   = intent.getExtras().get("data");
  int size     = bmp.getRowBytes() * bmp.getHeight();
  ByteBuffer b = ByteBuffer.allocate(size);

  bmp.copyPixelsToBuffer(b);

  byte[] bytes = new byte[size];

  try {
     b.get(bytes, 0, bytes.length);
  } catch (BufferUnderflowException e) {
     // always happens
  }
  // do something with byte[]

Wenn ich mir den Puffer nach dem Aufruf copyPixelsToBufferder Bytes ansehe, sind alle 0 ... Die von der Kamera zurückgegebene Bitmap ist unveränderlich ... aber das sollte keine Rolle spielen, da sie eine Kopie erstellt.

Was könnte an diesem Code falsch sein?

Tom Fobear
quelle

Antworten:

652

Versuchen Sie so etwas:

Bitmap bmp = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bmp.recycle();
Mezm
quelle
9
Verursacht dies keine Probleme, wenn das Bild nicht vom Typ PNG ist?
pgsandstrom
7
wird nicht, weil die Bitmap ein decodiertes Bild ist, unabhängig davon, was es war, wie ein Pixel-Array. Es wird als PNG komprimiert, was bei der Komprimierung nicht an Qualität verliert
5
Besser ist die Rückspuloption von @Ted Hopp - das Komprimieren ist eine Verschwendung von CPU, es sei denn, Ihr Ziel ist ein codiertes Bild ....
Kaolin Fire
38
Nach meiner Erfahrung muss bei Systemen mit geringem Arbeitsspeicher wie Android darauf geachtet werden, bitmap.recycle () hinzuzufügen. Schließen Sie den Stream direkt nach der Komprimierung, um die Speicherverlustausnahme zu vermeiden.
Sohn Huy TRAN
10
Dieser Ansatz ist wirklich verschwenderisch von Zuweisungen. Sie ByteArrayOutputStreamwerden eine byte[]Größe zuweisen , die der byte[]Unterlage entspricht Bitmap, und dann ByteArrayOutputStream.toByteArray()erneut eine byte[]Größe derselben Größe zuweisen .
Zyamys
70

CompressFormat ist zu langsam ...

Versuchen Sie es mit ByteBuffer.

※※※ Bitmap zu Byte ※※※

width = bitmap.getWidth();
height = bitmap.getHeight();

int size = bitmap.getRowBytes() * bitmap.getHeight();
ByteBuffer byteBuffer = ByteBuffer.allocate(size);
bitmap.copyPixelsToBuffer(byteBuffer);
byteArray = byteBuffer.array();

※※※ Byte zur Bitmap ※※※

Bitmap.Config configBmp = Bitmap.Config.valueOf(bitmap.getConfig().name());
Bitmap bitmap_tmp = Bitmap.createBitmap(width, height, configBmp);
ByteBuffer buffer = ByteBuffer.wrap(byteArray);
bitmap_tmp.copyPixelsFromBuffer(buffer);
朱 西西
quelle
5
Da diese Frage das Android-Tag hat, kann das Zurückkonvertieren von Bytes zurück in eine Bitmap auch mit einem Einzeiler erfolgen: Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length) Wo bytesist Ihr Byte-Array
Automat
Vielleicht sollte Big / Small Endian in Betracht gezogen werden?
NeoWang
Wenn Sie das Byte-Array in der lokalen Datenbank (Sqlite, Room) speichern möchten, sollten Sie wie in der oberen Antwort komprimieren!
J. Dragon
Beachten Sie jedoch, dass der Größenunterschied ohne Komprimierung dramatisch ist. Theoretisch könnte man Wikipedia lesen, aber in meinem Fall beträgt das komprimierte Ergebnis (gemäß der ersten Antwort) 20 MB, das andere (diese Antwort) 48 MB
Kirill Starostin
19

Hier ist die Bitmap-Erweiterung, .convertToByteArraydie in Kotlin geschrieben wurde.

/**
 * Convert bitmap to byte array using ByteBuffer.
 */
fun Bitmap.convertToByteArray(): ByteArray {
    //minimum number of bytes that can be used to store this bitmap's pixels
    val size = this.byteCount

    //allocate new instances which will hold bitmap
    val buffer = ByteBuffer.allocate(size)
    val bytes = ByteArray(size)

    //copy the bitmap's pixels into the specified buffer
    this.copyPixelsToBuffer(buffer)

    //rewinds buffer (buffer position is set to zero and the mark is discarded)
    buffer.rewind()

    //transfer bytes from buffer into the given destination array
    buffer.get(bytes)

    //return bitmap's pixels
    return bytes
}
Tomas Ivan
quelle
18

Müssen Sie den Puffer möglicherweise zurückspulen?

Dies kann auch passieren, wenn der Schritt (in Bytes) der Bitmap größer ist als die Zeilenlänge in Pixel * Bytes / Pixel. Stellen Sie die Länge der Bytes b.remaining () anstelle der Größe ein.

Ted Hopp
quelle
6
rewind()ist der Schlüssel. Ich bekam das gleiche BufferUnderflowExceptionund spulte den Puffer zurück, nachdem ich ihn gefüllt hatte, um dies zu beheben.
tstuts
9

Verwenden Sie die folgenden Funktionen, um die Bitmap in Byte [] zu codieren und umgekehrt

public static String encodeTobase64(Bitmap image) {
    Bitmap immagex = image;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    immagex.compress(Bitmap.CompressFormat.PNG, 90, baos);
    byte[] b = baos.toByteArray();
    String imageEncoded = Base64.encodeToString(b, Base64.DEFAULT);
    return imageEncoded;
}

public static Bitmap decodeBase64(String input) {
    byte[] decodedByte = Base64.decode(input, 0);
    return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
}
Amol Suryawanshi
quelle
6

Ihr Byte-Array ist zu klein. Jedes Pixel benötigt 4 Bytes, nicht nur 1. Multiplizieren Sie also Ihre Größe * 4, damit das Array groß genug ist.

MindJuice
quelle
4
Sein Byte-Array ist groß genug. getRowBytes()Berücksichtigt die 4 Bytes pro Pixel.
tstuts
3

Ted Hopp ist korrekt, aus der API-Dokumentation:

public void copyPixelsToBuffer (Buffer dst)

"... Nachdem diese Methode zurückgekehrt ist, wird die aktuelle Position des Puffers aktualisiert: Die Position wird um die Anzahl der in den Puffer geschriebenen Elemente erhöht."

und

public ByteBuffer get (byte[] dst, int dstOffset, int byteCount)

"Liest Bytes von der aktuellen Position in das angegebene Byte-Array, beginnend mit dem angegebenen Offset, und erhöht die Position um die Anzahl der gelesenen Bytes."

Captain Crunch
quelle
2

Um OutOfMemoryFehler bei größeren Dateien zu vermeiden , würde ich die Aufgabe lösen, indem ich eine Bitmap in mehrere Teile aufteile und die Bytes ihrer Teile zusammenführe.

private byte[] getBitmapBytes(Bitmap bitmap)
{
    int chunkNumbers = 10;
    int bitmapSize = bitmap.getRowBytes() * bitmap.getHeight();
    byte[] imageBytes = new byte[bitmapSize];
    int rows, cols;
    int chunkHeight, chunkWidth;
    rows = cols = (int) Math.sqrt(chunkNumbers);
    chunkHeight = bitmap.getHeight() / rows;
    chunkWidth = bitmap.getWidth() / cols;

    int yCoord = 0;
    int bitmapsSizes = 0;

    for (int x = 0; x < rows; x++)
    {
        int xCoord = 0;
        for (int y = 0; y < cols; y++)
        {
            Bitmap bitmapChunk = Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkWidth, chunkHeight);
            byte[] bitmapArray = getBytesFromBitmapChunk(bitmapChunk);
            System.arraycopy(bitmapArray, 0, imageBytes, bitmapsSizes, bitmapArray.length);
            bitmapsSizes = bitmapsSizes + bitmapArray.length;
            xCoord += chunkWidth;

            bitmapChunk.recycle();
            bitmapChunk = null;
        }
        yCoord += chunkHeight;
    }

    return imageBytes;
}


private byte[] getBytesFromBitmapChunk(Bitmap bitmap)
{
    int bitmapSize = bitmap.getRowBytes() * bitmap.getHeight();
    ByteBuffer byteBuffer = ByteBuffer.allocate(bitmapSize);
    bitmap.copyPixelsToBuffer(byteBuffer);
    byteBuffer.rewind();
    return byteBuffer.array();
}
Ayaz Alifov
quelle
0

Versuchen Sie dies, um String-Bitmap oder Bitmap-String zu konvertieren

/**
 * @param bitmap
 * @return converting bitmap and return a string
 */
public static String BitMapToString(Bitmap bitmap){
    ByteArrayOutputStream baos=new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG,100, baos);
    byte [] b=baos.toByteArray();
    String temp=Base64.encodeToString(b, Base64.DEFAULT);
    return temp;
}

/**
 * @param encodedString
 * @return bitmap (from given string)
 */
public static Bitmap StringToBitMap(String encodedString){
    try{
        byte [] encodeByte=Base64.decode(encodedString,Base64.DEFAULT);
        Bitmap bitmap= BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
        return bitmap;
    }catch(Exception e){
        e.getMessage();
        return null;
    }
}
Mohammad nabil
quelle