图片的二次采样

1.为什么要进行图片的二次采样?

主要是避免OOM。假设客户端需要加载一张图片,图片尺寸为3000*3000(单位/像素),那么计算一下,如果客户端想显示原图,按一个像素四个字节算,
3000 * 3000 * 4 / 1024 / 1024 = 34 M,想想看客户端一个应用程序的运行内存就十几M,你一下显示一个30多M的图片,直接crash了。

2.怎么解决?

这里就需要对图片进行二次采样。
原理:
BitmapFactory内部的图片解码,形成Bitmap是通过底层C/C++来实现的,有专门的图片界面库,可以通过参数来获取图片的尺寸,以及设置针对颜色加载的采样比率,采样比率就是把多个像素采样成一个像素,图片自然就变小了,最终传递给Java级别的对象,内存就变小了,图片也就变小了。

步骤:
第一步:在加载网络、文件的图片时,进行图片的解码BitmapFactory.decode(),只进行图片的尺寸获取,不进行实际的Bitmap创建,因此,第一次解码,不会占用太多的内存,可以获取图片的宽和高;

第二步:根据图片真实的宽高,以及客户端希望图片加载后的尺寸,进行一个计算,形成一种图片解码时缩小采样的一个数值,这个数值,可以直接运用在BitmapFactory上,加载到内存的Bitmap,就是变小的,内存是小图片的内容,不是原始图片的内存;

3.参数说明

3.1BitmapFactory中的Options说明
1)成员变量作为配置信息传给解码器
2)变量分为两部分:in开头的、out开头的
3)In开头的:用于个解码器传递参数
4)Out开头的:用于从解码器获取结果

3.2inSampleSize 采样比率
1)最好是2的幂,因为这种C语言解码效率最高
2)采样比率有一个官方的算法:以对角线的方式进行缩放比率的计算

/**
     * 计算图片二次采样的采样率,使用获取图片宽高之后的Options作为第一个参数
     * @param options
     * @param reqWidth
     * @param reqHeight
     * @return
     *
     * --by Google
     */
    private 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;

        //只有当请求的宽度、高度 > 0时,进行缩放
        //否则,图片不进行缩放
        if(reqHeight > 0 && reqWidth > 0){
            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;
    }

这里写图片描述

4.使用:

注释很详细了,不细说

 /**
     * 获取二次采样图片
     * @param data
     * @param requestWidth
     * @param requestHeight
     * @return
     */
    public static Bitmap getDownDimensionBitmap(byte[] data, int requestWidth, int requestHeight){
        Bitmap bitmap = null;
        if(data != null){
            //按照原始的图片尺寸,进行Bitmap的生存
            //按照Bitmap生成,是按照图片的原始宽高,进行生成,并且每一个像素占用4个字节 ARGB
//                ret = BitmapFactory.decodeByteArray(data, 0, data.length);

            //采用二次采样(缩小图片尺寸的方式)
            //1.步骤1 获取原始图片的宽高信息,用于进行采样的计算

            //1.1创建Options ,给BitmapFactory的内部解码器设置参数
            BitmapFactory.Options options = new BitmapFactory.Options();
            //1.2设置inJustDecodeBounds 来控制解码器,只会进行图片宽高的获取,不会获取图片
            //不占用内存,当使用这个参数,代表BitmapFactory.decodexxx()不会返回bitmap
            options.inJustDecodeBounds = true;

            //解码,使用options参数 设置解码方式
            BitmapFactory.decodeByteArray(data, 0, data.length, options);

            //2.步骤2 根据图片的真实尺寸,与当前需要显示的尺寸,进行计算,生成采样率

            //2.1
            //int picW = options.outWidth;
            //int picH = options.outHeight;

            //2.2准备 显示在手机上 256x128 128x64
            //尺寸是根据程序需要来设置的

//                int reqW = 256;
//                int reqH = 128;

            //2.3计算 设置 图片采样率
            options.inSampleSize = calculateInSampleSize(options, requestWidth, requestHeight);//宽度的1/32  高度的1/32

            //2.4开放 解码,实际生成Bitmap
            options.inJustDecodeBounds = false;

            //2.4.1 Bitmap.Config的说明
            //要求解码器对于每一个采样的像素,使用RGB_565 存储方式
            //一个像素,占用两个字节,比ARGB_8888笑了一半
            //如果解码器不能使用指定配置,就自动使用ARGB_8888
            options.inPreferredConfig = Bitmap.Config.RGB_565;

            //2.4.2是一个过时的设置,可以及时清除内存
            options.inPurgeable = true;

            //2.5使用设置采样的参数,来进行 解码,获取bitmap
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
        }
        return bitmap;
}

源码下载

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值