设置图片inSampleSize但是内存没变?或许你应该看看这个
来源:互联网 发布:易阳指炒股软件 编辑:程序博客网 时间:2024/06/05 01:59
对于安卓开发来说,内存溢出(oom)是安卓程序员不可绕过的坎,特别是对于大图片来说,加载时候的大内存更是常常让人胆战心惊。
很多安卓程序员都知道,避免图片加载大内存的最常用方法,那就是用BitmapFactory的options,设置这个options的inSampleSize来达到将图片按照实际显示大小去缩小自己图片,来达到减少内存。
若是你去百度inSampleSize,那么你会看到最多的用法是这样的:
private Bitmap getimage(String srcPath) { BitmapFactory.Options newOpts = new BitmapFactory.Options(); //开始读入图片,此时把options.inJustDecodeBounds 设回true了 newOpts.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//此时返回bm为空 newOpts.inJustDecodeBounds = false; int w = newOpts.outWidth; int h = newOpts.outHeight; //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为 float hh = 800f;//这里设置高度为800f float ww = 480f;//这里设置宽度为480f //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 int be = 1;//be=1表示不缩放 if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 be = (int) (newOpts.outWidth / ww); } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 be = (int) (newOpts.outHeight / hh); } if (be <= 0) be = 1; newOpts.inSampleSize = be;//设置缩放比例 //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 bitmap = BitmapFactory.decodeFile(srcPath, newOpts); return compressImage(bitmap);//压缩好比例大小后再进行质量压缩 }
看起来好像完全没有问题,根据自己想要的的图片大小,然后去计算将原图缩放的inSampleSize,然后赋值给bitmap以达到缩放图片大小。
很多人看到这样算法便喜不自胜急忙将它复制到自己工程,可是复制进去之后他们却傻眼了,内存跟以前没用时候差不多啊。
为什么会这样?
因为,inSampleSize只能为整数啊。
我们举个例子,假如有一张高度为700的图片,你想把它缩放为500,你要是用上面那个算法去算,你会发现,你算出来的inSampleSize其实为1!!!
而1,那就是图片不变,没有压缩
在这里说一下,inSampleSize的值只能为2的倍数,1,4,8,16……
1的话是不变,2的话是图片变为原来4分之一大小,8是变为原来64分之一大小,以此类推
所以到了最后,你会发现你想要压缩的图片其实根本没有被压缩。
好吧,就算有变,但其实也很难,甚至几乎不可能变到你想要的图片大小,就比如上面说的那个例子,无论你设置inSampleSize为什么值,你都会发现,你最终得到的图片要么太大要么太小。
但是安卓怎么可能那么垃圾,
对的,安卓才不会这么垃圾呢,
其实与inSampleSize相关的还有几个参数,比如inScaled,inTargetDensity,inDensity。
这些参数其实非常有用,与inSampleSize一起用才会完美。
其中:
inScaled:将它设置为true,那么代表这张图片可以缩放
inDensity:图片的原来密度,默认一般为160.
inTargetDensity:图片的目标密度,图片操作之后的密度
其实你设置一张图片的BitmapFactory的options,这张图片的输出宽高是这样决定的:
输出图片的宽高= (原图片的宽高 * (inTargetDensity / inDensity)) / inSampleSize
所以你要是现将一张700的图片缩小为600,你可以计算一下图片的inTargetDensity,如下面方法
/** * 获取特定大小缩略图 * @param imageid 图片资源id * @param size 你想要获取的图片大小尺寸 * @return */ public Bitmap getSampleBitmap2(int imageid,int size){ BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds=true; BitmapFactory.decodeResource(getResources(),imageid,options); options.inPreferredConfig = Bitmap.Config.ARGB_8888; options.inSampleSize= calculateInSampleSize(options,size); //设置图片可以缩小 options.inScaled = true; int calsize=options.outHeight>options.outWidth?options.outWidth:options.outHeight; /** * 计算图片缩小的目标密度,在这里说一下,有一条公式: * 输出图片的宽高= (原图片的宽高 * (inTargetDensity / inDensity)) / inSampleSize * 一般来说,图片的options.inDensity默认为160 * 所以inTargetDensity计算公式为:(希望输出的宽高*options.inDensity)/(原来图片的宽高/options.inSampleSize) */ options.inTargetDensity =(size*options.inDensity)/(calsize/options.inSampleSize); options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeResource(getResources(),imageid,options); return bitmap; }
//谷歌源码里面的计算simplesize方法, public int calculateInSampleSize(BitmapFactory.Options options, int size) { int reqWidth,reqHeight; // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; if(options.outHeight>options.outWidth){ reqWidth=size; reqHeight=size*options.outHeight/options.outWidth; }else{ reqWidth=size*options.outWidth/options.outHeight; reqHeight=size; } int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and // keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
比如我将一张宽700图片缩小为宽450的图片,在没设置inTargetDensity的时候
计算出来的inSampleSize为1,图片尺寸很大,没有变
所占用内存:
差不多40M
而在设置了inTargetDensity 之后
计算出来的inSampleSize仍然为1,但是图片尺寸却变为我想要获取的大小450了!!!
而所占用的内存:
只有14M左右!!!!!!!!!!
40?14!是不是感觉世界瞬间美好很多啦~
对了,后面顺便说一下,若你将根据这个方法得到的图片赋值给另一个bitmap的时候,可能会出现,这个被赋值的bitmap图片虽然图片大小不变,但是显示变了,那是因为这个inTargetDensity 属性不会自动赋值给新的bitmap,可以这样做
//创建一张新的bitmap,跟传入图片一样宽的正方形bitmap, Bitmap b=Bitmap.createBitmap(bitmapSize,bitmapSize, Bitmap.Config.ARGB_8888); //将图片密度修改为上面那张的图片密度 b.setDensity(bitmap.getDensity());
这样新得到的b图片就会跟原来那张一样了
- 设置图片inSampleSize但是内存没变?或许你应该看看这个
- 学习速度变慢?你或许应该跳槽了
- 学习速度变慢?或许应该跳槽
- 如果你看不懂KMP算法,一定要看看这个视频!!!!!!!!!!!虽然讲的慢,但是很详细!!!!
- 网页刷不开,那是你没改这个设置
- 你或许应该知道的LLVM
- 自控力太差?学编程的时候总是网上乱逛?你应该看看这个!
- 还在加班么?看看这个,也许你还需要加班,但是你的工作会轻松很多。
- 当没当父母都应该看看
- 看看这个适合你不?
- 看看你应该到哪里
- 图片缩放 inJustDecodeBounds inSampleSize
- H5适配逼疯人!这个方案或许能帮到你
- 看看你的变富机会
- 看看你眼睛有没毛病?
- vim设置tabstop,自动缩进没变
- 图片缩放 inJustDecodeBounds inSampleSize matrix
- CorelDraw应该怎么样才能学好描图技巧看看这个就能懂
- 机械键盘分类与选购技巧
- windows下进行FCN图像训练分割
- python模块opencv之图片操作(1)
- 遇到的一些前端JQuery问题汇总
- androidstudio3.0开发ndk
- 设置图片inSampleSize但是内存没变?或许你应该看看这个
- 基于OpenConnect 构建的SSL VPN解决方案
- Hive报错:Unable to instantiate org.apache.hadoop.hive.metastore.HiveMetaStoreClient
- 利用Shell将MySQL数据表导出为csv文件
- <jsp:include page>和<%@ include file%>的区别
- crontab 指定脚本运行的根目录
- 内容显示到iframe的特定区域
- .Net文档图像处理工具包GdPicture.NET发布v14.0.25,提升1D条形码引擎
- Python中文文档网站推荐:http://python.usyiyi.cn/