【问题标题】:Android: Bitmap compression is causing out of memory problemsAndroid:位图压缩导致内存不足问题
【发布时间】:2018-10-15 08:11:18
【问题描述】:

我正在尝试压缩从图库中挑选或由相机捕获的位图,然后再发送到服务器。现在我按照以下步骤进行操作:

1) 获取图片的路径。

2) 从此路径获取位图。

3) 检查位图的初始宽度和高度,并将它们与最大宽度和高度进行比较,然后使用比例因子调整宽度和高度。

4) 使用 exif 正确检查和旋转位图。

5) 最终降低质量以获得最终的压缩位图。

代码:

    private static final float max_width = 1280.0f;
    private static final float max_height = 1280.0f;
    private static final float max_ratio = max_width/max_height; 

    private void CompressImage(String path , Bitmap bitmap_original){



     //get width and height of original bitmap

     int original_width = bitmap_original.getWidth();
     int original_height = bitmap_origianl.getHeight();

     float original_ratio = (float)width/(float)height;

     if(original_height > max_height || original_width > max_width){
      //adjust bitmap dimensions

       int width = 0;
       int height = 0;

       if(original_ratio<max_ratio){
       width= (int)((max_height/original_height)*original_width);
       height=(int) max_height;  

       }else if(original_ratio>max_ratio){
        height= (int)((max_width/original_width)*original_height);
        width= (int)max_width;
       }else{
         height = max_height; 
         width = max_width;  
       }

       //adjust the bitmap 
        Bitmap adjusted_bitmap = Bitmap.createScaledBitmap(bitmap_original,width,height,false);


       //check rotation
       Matrix matrix = new Matrix();  
       try{
       ExifInterface exif = new ExifInterface(path);
       int original_orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION , ExifInterface.ORIENTATION_UNDEFINED);

         if(original_orientation == ExifInterface.ORIENTATION_ROTATE_90){

          matrix.setRotate(90);

         }else if(original_orientation == ExifInterface.ORIENTATION_180){

          matrix.setRotate(180);

         }else if(original_orientation == ExifInterface.ORIENTATION_270){

          matrix.setRotate(270);
         }

         Bitmap rotated_adjusted_bitmap = Bitmap.createBitmap(adjusted_bitmap , 0 , 0 , adjusted_bitmap.getWidth(), adjusted_bitmap.getHeight(),matrix,true);


         //lower the quality

          ByteArrayOutputStream out = new ByteArrayOutputStream();
          adjusted_rotated_bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
          Bitmap adjusted_rotated_lowquality_bitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));  

       }catch(IOException e){


        }


      }else{
      //keep bitmap as is
      Bitmap adjusted_bitmap = bitmap_original;
      }



     }

问题

上述一切正常,但问题是在某些情况下应用程序会因内存不足异常而崩溃。

我的代码有问题吗?

我对位图和压缩了解不多。

感谢您的帮助。

【问题讨论】:

  • 显示图像时是否崩溃?还是您将图像发送到服务器而不显示?
  • @MdSufiKhan 只是压缩部分有时会因为内存不足错误而阻塞 UI。
  • @MdSufiKhan 显示是由 glide 处理的,但我不知道为什么压缩有时会失败......可能是因为位图是高分辨率的。
  • 那是肯定的位图是高分辨率的。您是否尝试在单独的线程中压缩?

标签: android jpeg android-bitmap image-compression


【解决方案1】:

当您从图库中选择图片时,您可以获得图片 uri:

Uri myUri = data.getData();

在将图像发送到服务器之前,您需要将该 uri 转换为 byteArray[]

如下:

    Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),myUri);

   ByteArrayOutputStream baos = new ByteArrayOutputStream();

   bitmap.compress(Bitmap.CompressFormat.PNG,0,baos);
                        byteArray[] bArray = baos.toByteArray();
    If you want you can get the name of image as:
     try (Cursor returnCursor = getContentResolver().query(myUri, null, null, null, null)) {
                        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                        int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
                        returnCursor.moveToFirst();
                           String FileName = returnCursor.getString(nameIndex);}

【讨论】:

    【解决方案2】:

    位图通常需要时间,有时还会阻塞 I/O。因此,在 UI 线程上调用 imageWithText 并不是一个好习惯。

    Glide 被设计成灵活的,这个问题表明 性格非常好。

    下面的“滑翔方式”,我强烈推荐。

    ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
    yourBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); 
    Glide.with(this).load(stream.toByteArray())
         .asBitmap() .error(R.drawable.ic_thumb_placeholder) 
         .transform(new CircleTransform(this)).into(imageview);
    

    更多详情请查看以下链接

    Is there a way to load image as bitmap to Glide

    【讨论】:

    • 在发送到服务器之前应该如何压缩位图?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    相关资源
    最近更新 更多