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?

Tom Fobear
sumber

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();
Mezm
sumber
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);
朱 西西
sumber
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
}
Tomas Ivan
sumber
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.

Ted Hopp
sumber
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);
}
Amol Suryawanshi
sumber
6

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

MindJuice
sumber
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."

KaptenCunch
sumber
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();
}
Ayaz Alifov
sumber
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;
    }
}
Mohammad nabil
sumber