将Java位图转换为字节数组

Posted

技术标签:

【中文标题】将Java位图转换为字节数组【英文标题】:converting Java bitmap to byte array 【发布时间】:2011-06-26 17:27:16 【问题描述】:
  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...从相机返回的位图是不可变的...但这不重要,因为它正在复制。

这段代码有什么问题?

【问题讨论】:

【参考方案1】:

也许你需要倒带缓冲区?

此外,如果位图的步幅(以字节为单位)大于以像素 * 字节/像素为单位的行长度,则可能会发生这种情况。将字节的长度设为 b.remaining() 而不是 size。

【讨论】:

rewind() 是关键。我得到了相同的BufferUnderflowException 并在填充缓冲区后倒带解决了这个问题。【参考方案2】:

试试这样的:

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

【讨论】:

如果图像不是PNG类型,这不会导致问题吗? 不会,因为位图是解码的图像,无论是什么,就像一个像素阵列。它将压缩为 PNG,压缩时不会损失质量 @Ted Hopp 的倒带选项更好——压缩它会浪费 CPU,除非您的目标是编码图像...... 以我的经验,在android等低内存系统上,一定要注意添加bitmap.recycle();压缩后,关闭流,避免内存泄漏异常。 这种方式真的很浪费分配。您的ByteArrayOutputStream 将分配一个大小等于支持您的Bitmapbyte[] 大小的byte[],然后ByteArrayOutputStream.toByteArray() 将再次分配另一个相同大小的byte[]【参考方案3】:

您的字节数组太小。每个像素占用 4 个字节,而不仅仅是 1,所以将大小乘以 4,这样数组就足够大了。

【讨论】:

他的字节数组足够大。 getRowBytes() 考虑每个像素 4 个字节。【参考方案4】:

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);

【讨论】:

由于这个问题有 Android 标签,将字节转换回位图也可以使用单线完成:Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length) 其中bytes 是您的字节数组 也许应该考虑大/小端? 如果要将字节数组保存在本地DB(Sqlite,Room)中,应该像上面的答案一样压缩! 但是请注意,如果没有压缩,大小差异会很大。理论上你可以阅读***,但例如在我的情况下,压缩结果(根据第一个答案)是 20 MB,另一个(这个答案)是 48 MB【参考方案5】:

Ted Hopp 是正确的,来自 API 文档:

public void copyPixelsToBuffer (Buffer dst)

"... 该方法返回后,缓冲区的当前位置被更新:该位置增加了写入缓冲区的元素个数。 "

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

“从当前位置读取字节到指定的字节数组,从指定的偏移量开始,并将位置增加读取的字节数。”

【讨论】:

【参考方案6】:

使用以下函数将位图编码为字节[],反之亦然

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);

【讨论】:

【参考方案7】:

为了避免较大文件出现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();

【讨论】:

【参考方案8】:

试试这个转换 String-Bitmap 或 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;
    

【讨论】:

【参考方案9】:

这是用 Kotlin 编写的位图扩展 .convertToByteArray

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

【讨论】:

“A/位图:错误,无法在此处访问无效/释放的位图!”【参考方案10】:

我认为这样就可以了-

public static byte[] convertBitmapToByteArray(Bitmap bitmap)
        ByteBuffer byteBuffer = ByteBuffer.allocate(bitmap.getByteCount());
        bitmap.copyPixelsToBuffer(byteBuffer);
        byteBuffer.rewind();
        return byteBuffer.array();
    

【讨论】:

以上是关于将Java位图转换为字节数组的主要内容,如果未能解决你的问题,请参考以下文章

将位图转换为字节数组

如何将字节数组转换为位图实例 (.NET)?

将NV21字节数组转换为位图可读格式[重复]

如何将字节数组中的图像文件数据转换为位图?

Xamarin 安卓。将字节数组转换为位图。 Skia 解码器返回 false

Android:如何用相机拍照并将位图转换为字节数组并保存到sqlite db?