博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转)解决 bitmap size exceeds VM budget (Out Of Memory 内存溢出)的问题
阅读量:7156 次
发布时间:2019-06-29

本文共 3337 字,大约阅读时间需要 11 分钟。

在做图片处理的时候最常遇到的问题估计就是Out Of Memory (内存溢出)了

网上对这种问题的解决方案很多,原来无非就是压缩图片大小

本不该重复造轮子,但实际中却遇见了问题,写出来希望后来者能引以为戒,并给出一个自我感觉不错的方案

 

常用的一种解决方案:

 

FileInputStream f = new FileInputStream(file);

BitmapFactory.Options options = new BitmapFactory.Options();   
options.inSampleSize = 2;//将图片大小改为原来的1/4
Bitmap bm = BitmapFactory.decodeStream(f, null, options);

 

 

其中options.inSampleSize定义如下:

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder will try to fulfill this request, but the resulting bitmap may have different dimensions that precisely what has been requested. Also, powers of 2 are often faster/easier for the decoder to honor.

也就是说options.inSampleSize = 2就是将原图片的高和宽都设为1/2(单位为像素),整体图片也就缩小成原来的1/4之一了

这当然是一种很好的解决方案,只需根据自己的需要设置缩放比就行。

 

但这仅仅解决了一部分问题

试想一下,如果每张图片的大小都不一样,而要显示在相同的控件中,这时的缩放比(options.inSampleSize)该设置成多少呢?

如果设置缩放基本不够小,对于大像素图片的处理依然会出现内存溢出,设置得太大又会导致图片失真

这真是个头疼的问题。

如果能够根据图片大小自动计算缩放比那该多好啊!

 

别急,google已经为我们提供了这么一个方法(出自源码 暂且保存为BitmapUtiles.java 方便以后使用):

 

public class BitmapUtils

{
  
 public static int computeSampleSize(BitmapFactory.Options options, 
         int minSideLength, int maxNumOfPixels) { 
     int initialSize = computeInitialSampleSize(options, minSideLength, 
             maxNumOfPixels); 
  
     int roundedSize; 
     if (initialSize <= 8) { 
         roundedSize = 1; 
         while (roundedSize < initialSize) { 
             roundedSize <<= 1; 
         } 
     } else { 
         roundedSize = (initialSize + 7) / 8 * 8; 
     } 
  
     return roundedSize; 
 } 
  
  
 private static int computeInitialSampleSize(BitmapFactory.Options options, 
         int minSideLength, int maxNumOfPixels) { 
     double w = options.outWidth; 
     double h = options.outHeight; 
  
     int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math 
             .sqrt(w * h / maxNumOfPixels)); 
     int upperBound = (minSideLength == -1) ? 128 : (int) Math.min( 
             Math.floor(w / minSideLength), Math.floor(h / minSideLength)); 
  
     if (upperBound < lowerBound) { 
         // return the larger one when there is no overlapping zone. 
         return lowerBound; 
     } 
  
     if ((maxNumOfPixels == -1) && (minSideLength == -1)) { 
         return 1; 
     } else if (minSideLength == -1) { 
         return lowerBound; 
     } else { 
         return upperBound; 
     } 
 } 
}

 

我们只需要这样使用就好了:

 

 

 

FileInputStream f = new FileInputStream(file);

FileDescriptor fd = f.getFD();
   
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd, null, options);

options.inSampleSize = BitmapUtils.computeSampleSize(options, 80, 128*128);

options.inJustDecodeBounds = false;

Bitmap bm = BitmapFactory.decodeStream(f, null, options);

 

 

 

其中需要注意的是options.inJustDecodeBounds这个属性,API解释如下:

If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.

在设置为true的情况下不会返回bitmap,即不会占用内存,但可以计算bitmap的size大小(BitmapFactory.decodeFileDescriptor(fd, null, options) 由options带回宽、高)

此时的操作就是为了得到高、宽用于后面缩放比的计算

BitmapUtils.computeSampleSize(options, 80, 128*128)中

80是最小边长,128*128是期望得到的图像像素

 

特别注意的是,计算完宽高后一定要将改属性设置为false,否则BitmapFactory.decodeStream会一直返回null

 

OK,讲得够详细了

 

转自:

转载地址:http://tqhgl.baihongyu.com/

你可能感兴趣的文章
保险行业邮件归档案例
查看>>
我的友情链接
查看>>
mysql笔记
查看>>
我的友情链接
查看>>
【storm集群】storm 工作目录不停生成hs_err_pidXXX.log
查看>>
MySQL主从复制的原理及实现过程(mysql-5.5的同步、半步复制过程)
查看>>
C/C++中堆和栈的区别--李家凯老师
查看>>
PopupWindow的使用
查看>>
一次观察NETGEAR的log引起的小排查
查看>>
浅谈软件自动化集成测试流程
查看>>
我的友情链接
查看>>
中国大学在创造“失业大军”?
查看>>
PHP关于数据的舍入归类:round、ceil、floor、number_format
查看>>
android内核剖析系列---JNI调用机制分析
查看>>
Java常用的23种设计模式
查看>>
svn常用命令
查看>>
Ubuntu下CPU/GPU模式YOLOv3代码运行
查看>>
你不知道的互联网金融的大众特征性
查看>>
Linux系统里如何彻底清空终端屏幕
查看>>
PostgreSQL获取表的Size
查看>>