AndroidAndroid

inSampleSize优化

2015-11-05  本文已影响3500人  EvilsoulM

废话不多说先贴上常用的方法吧

 public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int width = options.outWidth;
        final int height = options.outHeight;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            //计算图片高度和我们需要高度的最接近比例值
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            //宽度比例值
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            //取比例值中的较大值作为inSampleSize
            inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;
        }

        return inSampleSize;
    }

inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理),且在大于1时,该值只能为2的幂(当不为2的幂时,解码器会取与该值最接近的2的幂)。例如,当inSampleSize为2时,一个20001000的图片,将被缩小为1000500,相应地,它的像素数和内存占用都被缩小为了原来的1/4:

但是由于我们平时拍的照片都是长图,这种算法用在浏览相册图片的时候会导致压缩太过严重,导致照片不是很清楚
都是在1080 * 1776 (nexus 5)上load一张满屏图

width height Ratio
1536 2048 1
1944 2592 2
3264 2448 3
8264 2446 8

可以看出来如果我们图片是宽度大于高度的图片,图片ratio就会很大导致图片压缩太严重在显示可缩放的图片的时候,图片质量过于差。

    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int width = options.outWidth;
        final int height = options.outHeight;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            //使用需要的宽高的最大值来计算比率
            final int suitedValue = reqHeight > reqWidth ? reqHeight : reqWidth;
            final int heightRatio = Math.round((float) height / (float) suitedValue);
            final int widthRatio = Math.round((float) width / (float) suitedValue);

            inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;//用最大
        }

        return inSampleSize;
    }

使用上面优化过后的方法后

width height Ratio
1536 2048 1
1944 2592 1
3264 2448 2
8264 2446 4

在宽大于高的时候对于图片质量有了较大的提升

使用这种算法不适宜用于一些不太在意图片质量,或者不支持缩放图片的地方。正常情况下还是可以用官方的方法。或者在方法中判断宽和高如果宽大于高使用下面的方法计算SampleSize

再贴一个SDK文档的算法,还没有用过~

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;

    }

} 

//使用方式
opts.inSampleSize = computeSampleSize(opts, -1, 128*128);  

延伸:一个Bitmap到底占用多大内存?系统给每个应用程序分配多大内存?
· Bitmap占用的内存为:像素总数 * 每个像素占用的内存。在Android中,Bitmap有四种像素类型:ARGB_8888、ARGB_4444、ARGB_565、ALPHA_8,他们每个像素占用的字节数分别为4、2、2、1。因此,一个20001000的ARGB_8888类型的Bitmap占用的内存为20001000*4=8000000B=8MB。
· Android根据设备屏幕尺寸和dpi的不同,给系统分配的单应用程序内存大小也不同,具体如下表(表格取自Android 4.4 Compatibility Definition Document (CDD)):

屏幕尺寸 DPI 应用内存
small / normal / large ldpi / mdpi 16MB
small / normal / large tvdpi / hdpi 32MB
small / normal / large xhdpi 64MB
small / normal / large 400dpi 96MB
small / normal / large xxhdpi 128MB
xlarge mdpi 32MB
xlarge tvdpi / hdpi 64MB
xlarge xhdpi 128MB
xlarge 400dpi 192MB
xlarge xxhdpi 256MB
上一篇 下一篇

猜你喜欢

热点阅读