conversione di bitmap Java in array di byte


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[]

Quando guardo il buffer dopo che la chiamata ai copyPixelsToBufferbyte sono tutti 0 ... La bitmap restituita dalla telecamera è immutabile ... ma non dovrebbe importare dal momento che sta facendo una copia.

Cosa potrebbe esserci di sbagliato in questo codice?

Risposte:


652

Prova qualcosa del genere:

Bitmap bmp = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bmp.recycle();

9
Questo non causerà problemi se l'immagine non è di tipo PNG?
pgsandstrom,

7
non perché Bitmap è un'immagine decodificata indipendentemente da ciò che è stato, come un array di pixel. Comprimerà come un PNG, che non perderà qualità alla compressione

5
meglio è l'opzione di riavvolgimento di @Ted Hopp: comprimerlo è uno spreco di CPU a meno che il tuo obiettivo non sia un'immagine codificata ....
Fuoco di caolino

38
Nella mia esperienza, su un sistema a memoria insufficiente come Android, devo prestare attenzione per aggiungere bitmap.recycle (); subito dopo la compressione e chiudere il flusso per evitare l'eccezione della perdita di memoria.
Son Huy TRAN,

10
Questo approccio è davvero uno spreco di allocazioni. Il tuo ByteArrayOutputStreamassegnerà una byte[]di dimensioni pari al byte[]appoggiando la vostra Bitmap, poi ByteArrayOutputStream.toByteArray()sarà di nuovo allocare un altro byte[]della stessa dimensione.
Zyamys,

70

CompressFormat è troppo lento ...

Prova ByteBuffer.

※※※ Bitmap a 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 in 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);

5
Dato che questa domanda ha il tag Android, la conversione di byte in Bitmap può anche essere fatta con un solo liner: Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length) dov'è il bytestuo array di byte
automa

Forse il big / small endian dovrebbe essere considerato?
NeoWang,

Se vuoi salvare l'array di byte nel DB locale (Sqlite, Room), dovresti comprimerlo come la risposta superiore!
J.Dragon,

Si noti, tuttavia, che senza la compressione la differenza di dimensioni è drammatica. Per la teoria potresti leggere Wikipedia, ma per esempio nel mio caso il risultato compresso (secondo la prima risposta) è 20 MB, l'altro (questa risposta) è 48 MB
Kirill Starostin

19

Ecco l'estensione bitmap .convertToByteArrayscritta in Kotlin.

/**
 * 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
}

18

Hai bisogno di riavvolgere il buffer, forse?

Inoltre, ciò può accadere se il passo (in byte) della bitmap è maggiore della lunghezza della riga in pixel * byte / pixel. Crea la lunghezza dei byte b.remaining () anziché la dimensione.


6
rewind()è la chiave. Stavo ottenendo lo stesso BufferUnderflowExceptione riavvolgendo il buffer dopo averlo riempito risolto questo.
martedì

9

Utilizzare le funzioni seguenti per codificare bitmap in byte [] e viceversa

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

6

Il tuo array di byte è troppo piccolo. Ogni pixel occupa 4 byte, non solo 1, quindi moltiplica la tua dimensione * 4 in modo che l'array sia abbastanza grande.


4
Il suo array di byte è abbastanza grande. getRowBytes()accetta i 4 byte per pixel nell'account.
martedì

3

Ted Hopp è corretto, dalla documentazione API:

public void copyPixelsToBuffer (Buffer dst)

"... Dopo che questo metodo ritorna, la posizione corrente del buffer viene aggiornata: la posizione viene incrementata del numero di elementi scritti nel buffer."

e

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

"Legge i byte dalla posizione corrente nell'array di byte specificato, iniziando dall'offset specificato e aumenta la posizione del numero di byte letti."


2

Al fine di evitare OutOfMemoryerrori per file più grandi, risolverei il compito suddividendo una bitmap in più parti e unendo i byte delle loro parti.

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

0

Prova questo per convertire String-Bitmap o Bitmap-String

/**
 * @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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.