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

这段代码有什么问题?

【问题讨论】:

    标签: java android serialization bitmap bytebuffer


    【解决方案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();
                }
            

            【讨论】:

              猜你喜欢
              • 2010-09-26
              • 2018-05-06
              • 2013-01-14
              • 2013-07-29
              • 2012-11-09
              • 1970-01-01
              • 2019-12-13
              相关资源
              最近更新 更多