Java bitmap'in bayt dizisine dönüştürülmesi


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

copyPixelsToBufferBayt çağrısı 0 sonra arabellek baktığınızda ... Kameradan döndürülen bitmap değişmez ... ama bir kopya yaptığı için bu önemli değil.

Bu kodla ilgili sorun ne olabilir?

Yanıtlar:


652

Bunun gibi bir şey deneyin:

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

9
Görüntü PNG türünde değilse bu soruna neden olmaz mı?
pgsandstrom

7
Bitmap'in ne olursa olsun, bir piksel dizisi gibi kodu çözülmüş bir görüntü olması nedeniyle olmaz. Sıkıştırmada kaliteyi kaybetmeyecek bir PNG olarak sıkıştırılacaktır

5
@Ted Hopp'tan geri sarma seçeneği daha iyidir - hedefiniz kodlanmış bir görüntü olmadıkça sıkıştırmak CPU israfıdır ....
Kaolin Fire

38
Deneyimlerime göre, Android gibi düşük bellek sistemlerinde, bitmap.recycle (); sıkıştırmadan hemen sonra ve bellek sızıntısı istisnasını önlemek için akışı kapatın.
Son Huy TRAN

10
Bu yaklaşım tahsislerin gerçekten israfıdır. Sizin desteğinize eşit ByteArrayOutputStreambir byte[]boyut atarsınız , sonra yine aynı boyutta başka bir tane atarsınız. byte[]BitmapByteArrayOutputStream.toByteArray()byte[]
zyamys

70

CompressFormat çok yavaş ...

ByteBuffer'ı deneyin.

By Bitmap - bayt ※※※

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

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

※※※ bitmap bayt ※※※

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
Bu soru Android etiketine sahip olduğundan, baytları bir Bitmap'e dönüştürmek de tek bir astarla yapılabilir: bayt diziniz Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length) neredebytes
automaton

Belki büyük / küçük endian düşünülmelidir?
NeoWang

Bayt dizisini yerel DB'ye (Sqlite, Oda) kaydetmek istiyorsanız, üst yanıt gibi sıkıştırmalısınız!
J.Dragon

Bununla birlikte, sıkıştırma olmadan boyut farkının dramatik olduğunu unutmayın. Teori için wikipedia okuyabilirsiniz, ancak benim durumumda sıkıştırılmış sonuç (1. cevaba göre) 20 MB, diğeri (bu cevap) 48 MB
Kirill Starostin

19

İşte .convertToByteArrayKotlin'de yazılan bitmap uzantısı .

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

Belki de tamponu geri sarmanız mı gerekiyor?

Ayrıca, bitmap'in adım (bayt cinsinden) piksel * bayt / piksel cinsinden satır uzunluğundan daha büyükse bu olabilir. Bayt uzunluğunu boyut yerine b.remaining () yapın.


6
rewind()Anahtar mı. Ben de aynısını alıyordum BufferUnderflowExceptionve doldurduktan sonra tamponu geri sarmak bu sorunu çözdü.
tstuts

9

Bitmap'i bayt [] içine veya tam tersini kodlamak için aşağıdaki işlevleri kullanın

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

Bayt diziniz çok küçük. Her piksel sadece 1 değil 4 bayt alır, bu yüzden dizinin yeterince büyük olması için boyutunuzu * 4 ile çarpın.


4
Bayt dizisi yeterince büyük. getRowBytes()piksel başına 4 baytı hesaba katar.
tstuts

3

Ted Hopp, API Dokümantasyonundan doğrudur:

public void copyPixelsToBuffer (Buffer dst)

"... Bu yöntem döndükten sonra , arabelleğin geçerli konumu güncellenir: konum, arabelleğe yazılan öğe sayısı kadar artırılır."

ve

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

" Geçerli konumdan belirtilen bayt dizisine baytları, belirtilen ofsetten başlayarak okur ve konumu okunan bayt sayısı kadar artırır."


2

Daha OutOfMemorybüyük dosyalar için hatayı önlemek için, bir bitmap'i birkaç parçaya bölerek ve parçalarının baytlarını birleştirerek görevi çözerdim.

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

String-Bitmap veya Bitmap-String'i dönüştürmek için bunu deneyin

/**
 * @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;
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.