mengkonversi bitmap Java ke 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[]

Ketika saya melihat buffer setelah panggilan ke copyPixelsToBufferbyte adalah semua 0 ... Bitmap yang dikembalikan dari kamera tidak dapat diubah ... tapi itu tidak masalah karena ia sedang menyalin.

Apa yang salah dengan kode ini?

Jawaban:


652

Coba sesuatu seperti ini:

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

9
Bukankah ini akan menyebabkan masalah jika gambar bukan dari tipe PNG?
pgsandstrom

7
tidak akan karena Bitmap adalah gambar yang di-decode terlepas dari apa yang sebelumnya, seperti array piksel. Ini akan dikompres sebagai PNG, yang tidak akan kehilangan kualitas pada kompresi

5
lebih baik adalah opsi mundur dari @Ted Hopp - mengompresi itu adalah pemborosan CPU kecuali tujuan Anda adalah gambar yang disandikan ....
Kaolin Fire

38
Dalam pengalaman saya, pada sistem memori rendah seperti Android, harus diperhatikan untuk menambahkan bitmap.recycle (); tepat setelah kompresi, dan tutup aliran untuk menghindari pengecualian kebocoran memori.
Son Huy TRAN

10
Pendekatan ini benar-benar pemborosan alokasi. Anda ByteArrayOutputStreamakan mengalokasikan byte[]ukuran yang sama dengan byte[]dukungan Anda Bitmap, kemudian ByteArrayOutputStream.toByteArray()akan lagi mengalokasikan yang lain byte[]dengan ukuran yang sama.
zyamys

70

CompressFormat terlalu lambat ...

Coba ByteBuffer.

※※※ Bitmap ke 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 ke 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
Karena pertanyaan ini memiliki tag Android, mengonversi byte kembali ke Bitmap juga dapat dilakukan dengan satu-liner: di Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length) mana bytesarray byte Anda
automaton

Mungkin endian besar / kecil harus dipertimbangkan?
NeoWang

Jika Anda ingin menyimpan array byte di DB lokal (Sqlite, Room), Anda harus mengompres seperti jawaban atas!
J.Dragon

Perhatikan, bagaimanapun, bahwa tanpa kompresi perbedaan ukurannya dramatis. Untuk teori Anda bisa membaca wikipedia, tetapi misalnya dalam kasus saya hasil kompresi (sesuai jawaban 1) adalah 20 MB, yang lain (jawaban ini) adalah 48 MB
Kirill Starostin

19

Berikut ini adalah ekstensi bitmap yang .convertToByteArrayditulis di 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

Apakah Anda perlu memundurkan buffer, mungkin?

Juga, ini mungkin terjadi jika langkah (dalam byte) dari bitmap lebih besar dari panjang baris dalam piksel * byte / piksel. Buat panjang byte b.remaining () alih-alih ukuran.


6
rewind()adalah kuncinya. Saya mendapatkan yang sama BufferUnderflowExceptiondan memutar ulang buffer setelah mengisinya menyelesaikan ini.
tstuts

9

Gunakan fungsi di bawah ini untuk menyandikan bitmap ke byte [] dan sebaliknya

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

Array byte Anda terlalu kecil. Setiap piksel membutuhkan 4 byte, bukan hanya 1, jadi gandakan ukuran Anda * 4 sehingga arraynya cukup besar.


4
Array byte-nya cukup besar. getRowBytes()membawa 4 byte per piksel ke akun.
tstuts

3

Ted Hopp benar, dari Dokumentasi API:

public void copyPixelsToBuffer (Buffer dst)

"... Setelah metode ini kembali, posisi buffer saat ini diperbarui: posisinya bertambah dengan jumlah elemen yang ditulis dalam buffer."

dan

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

"Membaca byte dari posisi saat ini ke dalam array byte yang ditentukan, mulai dari offset yang ditentukan, dan meningkatkan posisi dengan jumlah byte yang dibaca."


2

Untuk menghindari OutOfMemorykesalahan pada file yang lebih besar, saya akan menyelesaikan tugas dengan memecah bitmap menjadi beberapa bagian dan menggabungkan byte bagian mereka.

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

Coba ini untuk mengonversi String-Bitmap atau 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;
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.