BitmapFactory: inSampleSize 的一些思考

文章讨论了Android开发中BitmapFactory.Options的inSampleSize属性如何影响图片加载,解释了其计算方法以减少内存消耗,防止OOM。同时指出Google推荐算法可能存在的问题,当inSampleSize值较大时可能影响图片质量。此外,文中提到了一个潜在的崩溃风险,即图片在不同密度资源目录下可能导致系统自动缩放,建议设置inScaled为false来避免不必要的缩放操作。

一. BitmapFactory.Options 中inSampleSize的取值问题

inSampleSize 设置大于 1 : 如果值大于 1 , 那么就会缩小图片 ;
解码器操作 : 此时解码器对原始的图片数据进行子采样 , 返回较小的 Bitmap 对象 ;

样本个数 : 样本的大小是在两个维度计算的像素个数 , 每个像素对应一个解码后的图片中的单独的像素点 ;
样本个数计算示例 :

如果 inSampleSize 值为 2 , 那么宽度的像素个数会缩小 2 倍 , 高度也会缩小两倍 ;整体像素个数缩小 4 倍 , 内存也缩小了 4 倍 ;

小于 1 取值 : 如果取值小于 1 , 那么就会被当做 1 , 1 相当于 2 的 0 次方 ;
取值要求 : 该值必须是 2 的幂次方值 , 2 的次方值 , 如 1 , 2 , 4 , 8 , 16 , 32
如果出现了不合法的值 , 就会就近四舍五入到最近的 2 的幂次方值

关于inSampleSize的取值问题Google已经给出了一个推荐的算法:(https://developer.android.com/topic/performance/graphics/load-bitmap)

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    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;
}

实际测试下还好,基本可以满足不OOM的需求,但是隐隐觉得当inSampleSize的值很大的时候,图片的压缩质量会不会太严重?比如说App内中的相册功能,采用这个算法放大的时候,图片会不会变得很不清楚?一时也没有找到特别好的压缩算法。

二. 图片的放置问题

按照Google给出的示例代码,使用inSampleSize前要先把 options.inJustDecodeBounds = true; 设置成true:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

然后再计算出inSampleSize,最后再进行decode,个人觉得这段代码还是有缺陷,拿我的手机来说吧,分辨率是14402560, 需要显示的ImageView宽度是1440810,需要加载的图片是1920*1080,通过上面Google的算法,算出inSampleSize的值为1,我把图片放置到xxxhdpi和xxhdpi的时候图片可以正常显示,但是我把图片放到mdpi和raw文件夹下的时候,程序一运行就Crash了,因为inSampleSize的默认值就是1,等于没有做任何处理,但是系统在加载时却会对图片再进行放大,一旦需要申请的字节数过多,系统就直接Crash了:

java.lang.RuntimeException: Canvas: trying to draw too large(132710400bytes) bitmap.

所以我觉得为了保险起见,最好在上面的代码中加上这么一句: options.inScaled = false;

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;   options.inScaled = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

保证不管我放置在任何文件夹,图片都不会被缩放。

来源:https://www.cnblogs.com/yongdaimi/p/11120590.html
https://cloud.tencent.com/developer/article/2247083

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值