设置图片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图片就会跟原来那张一样了

阅读全文
0 0
原创粉丝点击