chuyển đổi bitmap Java thành mảng 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[]

Khi tôi nhìn vào bộ đệm sau khi cuộc gọi tới copyPixelsToBuffercác byte đều bằng 0 ... Ảnh bitmap được trả về từ máy ảnh là bất biến ... nhưng điều đó không quan trọng vì nó đang sao chép.

Điều gì có thể sai với mã này?

Câu trả lời:


652

Hãy thử một cái gì đó như thế này:

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

9
Điều này có gây ra vấn đề gì không nếu hình ảnh không phải là loại PNG?
pssandstrom

7
sẽ không vì Bitmap là một hình ảnh được giải mã bất kể đó là gì, như một mảng pixel. Nó sẽ nén dưới dạng PNG, sẽ không mất chất lượng khi nén

5
tốt hơn là tùy chọn tua lại từ @Ted Hopp - nén nó là một sự lãng phí CPU trừ khi mục tiêu của bạn là một hình ảnh được mã hóa ....
Kaolin Fire

38
Theo kinh nghiệm của tôi, trên hệ thống bộ nhớ thấp như Android, phải chú ý thêm bitmap.recycle (); ngay sau khi nén và đóng luồng để tránh ngoại lệ rò rỉ bộ nhớ.
Sơn Huy TRẦN

10
Cách tiếp cận này thực sự lãng phí phân bổ. Bạn ByteArrayOutputStreamsẽ phân bổ một byte[]kích thước bằng với sự byte[]ủng hộ của bạn Bitmap, sau đó ByteArrayOutputStream.toByteArray()sẽ lại phân bổ một byte[]kích thước khác có cùng kích thước.
zyamys

70

CompressFormat quá chậm ...

Hãy thử ByteBuffer.

※2727 Bitmap sang byte ※

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

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

※ ※27 byte để 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
Kể từ khi câu hỏi này có tag Android, chuyển đổi byte trở lại một Bitmap cũng có thể được thực hiện với một lớp lót: Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length) nơi byteslà mảng byte của bạn
automaton

Có lẽ nên xem xét endian lớn / nhỏ?
NeoWang

Nếu bạn muốn lưu mảng byte trong DB cục bộ (Sqlite, Room), bạn nên nén như câu trả lời trên!
J.Dragon

Lưu ý, tuy nhiên, nếu không nén, sự khác biệt kích thước là rất lớn. Đối với lý thuyết bạn có thể đọc wikipedia, nhưng ví dụ trong trường hợp của tôi, kết quả nén (theo câu trả lời thứ 1) là 20 MB, câu trả lời khác (câu trả lời này) là 48 MB
Kirill Starostin

19

Đây là phần mở rộng bitmap được .convertToByteArrayviết trong 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

Bạn có cần phải tua lại bộ đệm, có lẽ?

Ngoài ra, điều này có thể xảy ra nếu sải chân (tính bằng byte) của bitmap lớn hơn độ dài hàng tính bằng pixel * byte / pixel. Tạo độ dài của byte b.remained () thay vì kích thước.


6
rewind()là chìa khóa Tôi đã nhận được cùng BufferUnderflowExceptionvà tua lại bộ đệm sau khi điền nó giải quyết điều này.
tstuts

9

Sử dụng các hàm bên dưới để mã hóa bitmap thành byte [] và ngược lại

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

Mảng byte của bạn quá nhỏ. Mỗi pixel chiếm 4 byte, không chỉ 1, vì vậy hãy nhân kích thước của bạn * 4 để mảng đủ lớn.


4
Mảng byte của anh đủ lớn. getRowBytes()mất 4 byte cho mỗi pixel vào tài khoản.
tstuts

3

Ted Hopp là chính xác, từ Tài liệu API:

public void copyPixelsToBuffer (Buffer dst)

"... Sau khi phương thức này trả về, vị trí hiện tại của bộ đệm được cập nhật: vị trí được tăng lên theo số lượng phần tử được ghi trong bộ đệm."

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

"Đọc byte từ vị trí hiện tại vào mảng byte được chỉ định, bắt đầu ở phần bù được chỉ định và tăng vị trí theo số byte được đọc."


2

Để tránh OutOfMemorylỗi cho các tệp lớn hơn, tôi sẽ giải quyết tác vụ bằng cách chia bitmap thành nhiều phần và hợp nhất các byte của các phần của chúng.

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

Hãy thử điều này để chuyển đổi Chuỗi-Bitmap hoặc Chuỗi Bitmap

/**
 * @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;
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.