Javaビットマップをバイト配列に変換する


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

copyPixelsToBufferバイトへの呼び出しがすべて0 になった後にバッファを見ると...カメラから返されるビットマップは不変です...しかし、コピーを実行しているので、それは問題ではありません。

このコードの何が問題になっているのでしょうか?

回答:


652

このようなものを試してください:

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

9
画像がPNGタイプでない場合、これは問題を引き起こしませんか?
pgsandstrom 2012

7
ビットマップは、ピクセル配列のように、何であるかに関係なく、デコードされた画像であるためです。PNGとして圧縮されますが、圧縮しても品質が低下しません

5
@Ted Hoppの巻き戻しオプションの方が良い—目標がエンコードされたイメージでない限り、圧縮するとCPUの無駄になります...
Kaolin Fire

38
私の経験では、Androidなどの低メモリシステムでは、bitmap.recycle();を追加することに注意する必要があります。圧縮の直後に、メモリリーク例外を回避するためにストリームを閉じます。
Son Huy TRAN

10
このアプローチは、実際に割り当てを浪費します。あなたがByteArrayOutputStream割り当てられますbyte[]サイズのに等しいbyte[]あなたを支持しBitmap、その後、ByteArrayOutputStream.toByteArray()再び割り当てられますさらに別のbyte[]同じ大きさの。
zyamys 2014年

70

CompressFormatが遅すぎる...

ByteBufferを試してください。

※※※ビットマップ→バイト※※※

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

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

※※※バイトからビットマップ※※※

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
この質問にはAndroidタグが含まれているため、バイトをビットマップに戻す変換はワンライナーでも実行できます。バイト配列はBitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length) どこbytes
オートマトン

おそらくビッグ/スモールエンディアンを検討する必要がありますか?
NeoWang

ローカルDB(Sqlite、Room)にバイト配列を保存する場合は、上の答えのように圧縮する必要があります。
J.ドラゴン

ただし、圧縮を行わないと、サイズの違いが劇的になることに注意してください。理論上はウィキペディアを読むこともできますが、たとえば私の場合、圧縮された結果(最初の回答によると)は20 MB、もう1つ(この回答)は48 MBです
Kirill Starostin

19

これは.convertToByteArrayKotlinで書かれたビットマップ拡張です。

/**
 * 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.remaining()にします。


6
rewind()キーです。私は同じことをしていて、BufferUnderflowExceptionそれを満たした後にバッファを巻き戻しましたがこれを解決しました。
2013

9

以下の関数を使用してビットマップをbyte []に​​、またはその逆にエンコードします

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

バイト配列が小さすぎます。各ピクセルは1バイトではなく4バイトを使用するので、配列に十分な大きさになるようにサイズ* 4を掛けます。


4
彼のバイト配列は十分な大きさです。 getRowBytes()ピクセルあたり4バイトを考慮に入れます。
2013

3

Ted Hoppは正しい、APIドキュメントから:

public void copyPixelsToBuffer (Buffer dst)

「...このメソッドが戻った後、バッファの現在の位置が更新されます。位置は、バッファに書き込まれた要素の数だけインクリメントされます。」

そして

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

現在の位置から指定されたオフセットで始まる指定されたバイト配列にバイトを読み取り、読み取られたバイト数だけ位置を増やします。」


2

OutOfMemory大きなファイルのエラーを回避するために、ビットマップをいくつかの部分に分割し、それらの部分のバイトをマージすることで、タスクを解決します。

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

文字列ビットマップまたはビットマップ文字列を変換するには、これを試してください

/**
 * @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;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.