美文网首页相机-相册
图片加载<第二篇>:BitmapFactory.Op

图片加载<第二篇>:BitmapFactory.Op

作者: NoBugException | 来源:发表于2019-05-13 17:41 被阅读265次
    (1)常用属性
    BitmapFactory.Options options = new BitmapFactory.Options();
    
    //默认值为false,如果设置成true,那么在解码的时候就不会返回bitmap,即bitmap = null。
    options.inJustDecodeBounds = false;
    
    //可以复用之前用过的bitmap
    options.inBitmap = null;
    
    //是该bitmap缓存是否可变,如果设置为true,将可被inBitmap复用
    options.inMutable = true;
    
    
    DisplayMetrics dm = getResources().getDisplayMetrics();
    //表示这个bitmap的像素密度,当inDensity为0时,系统默认赋值为屏幕当前像素密度
    options.inDensity = dm.densityDpi;
    
    //表示要被画出来时的目标像素密度,当inTargetDensity为0时,系统默认赋值为屏幕当前像素密度
    options.inTargetDensity = options.inDensity;
    
    //表示实际设备的像素密度
    options.inScreenDensity = 0;
    
    //这个参数可以改变bitmap分辨率大小,inSampleSize >= 1。
    //当inSampleSize < 1时,inSampleSize就默认是1。
    //假如:图片的宽和高分别是width、height,那么图片解码生成的bitmap的宽度是:width / inSampleSize,高度是:height / inSampleSize
    //inSampleSize影响bitmap的分辨率,从而影响bitmap占用内存的大小。
    options.inSampleSize = 1;
    
    //设置这个Bitmap是否可以被缩放,默认值是true,表示可以被缩放。
    options.inScaled = true;
    
    (2)图片加载之前先计算图片大小
    Bitmap bitmap = BitmapFactory.decodeFile(FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "temp.jpg");
    

    我们看一下上面的代码,那是解码一张本地图片,解码之后bitmap将占用内存空间,如果bitmap太大导致app性能降低,甚至导致OOM发生,为了防止这种现象,我们可以先计算本地图片的分辨率:

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    Bitmap bitmap = BitmapFactory.decodeFile(FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "temp.jpg", options );
    int imageHeight = options.outHeight;
    Log.d("aaa", "图片的高度:"+imageHeight);
    int imageWidth = options.outWidth;
    Log.d("aaa", "图片的宽度:"+imageWidth);
    

    inJustDecodeBounds设置true时,本地图片解码之后bitmap为null,只计算图片的宽度和高度。拿到图片宽度和高度之后可以根据我们自己的策略是否放大或缩小图片分辨率。

    (3)使用inBitmap复用bitmap

    inMutable设置成true,可以使当前bitmap对空间可被复用。

    (4)像素密度分析

    BitmapFactory.Options中与像素密度有关的主要有三个参数:inDensityinTargetDensityinScreenDensity

    配合inScaled参数可以控制图像缩放。

    我们先看一下源码

    /**
     * Set the newly decoded bitmap's density based on the Options.
     */
    private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
        if (outputBitmap == null || opts == null) return;
    
        final int density = opts.inDensity;
        if (density != 0) {
            outputBitmap.setDensity(density);
            final int targetDensity = opts.inTargetDensity;
            if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
                return;
            }
    
            byte[] np = outputBitmap.getNinePatchChunk();
            final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
            if (opts.inScaled || isNinePatch) {
                outputBitmap.setDensity(targetDensity);
            }
        } else if (opts.inBitmap != null) {
            // bitmap was reused, ensure density is reset
            outputBitmap.setDensity(Bitmap.getDefaultDensity());
        }
    }
    

    inDensity的默认值为0,会执行

    outputBitmap.setDensity(Bitmap.getDefaultDensity());
    

    bitmap的像素密度为屏幕默认像素密度,相当于

    DisplayMetrics dm = getResources().getDisplayMetrics();
    //表示这个bitmap的像素密度,当inDensity为0时,系统默认赋值为屏幕当前像素密度
    options.inDensity = dm.densityDpi;
    

    当我们给inDensity取值时,就会走另一个分支,接下来才是重点

    当inTargetDensity=0或者inDensity=inTargetDensity或者inDensity=inScreenDensity时,图像的像素密度是inDensity,否则,当inScaled = true或者图像为9Path图片时,最终图像的像素密度为inTargetDensity。

    inDensityinTargetDensityinScreenDensityinScaled配合使用可以对图片进行缩放,缩放的比例是targetDensity / density

    (5)inSampleSize

    修改像素密度只能修改图像的分辨率,但不能改变bitmap大小。
    而inSampleSize不仅可以修改分辨率,而且bitmap的大小也随便变化。

    假如默认情况(inSampleSize = 1)下,图像的分辨率是205x205,占用内存0.16031265M,那么如果将inSampleSize 设置成2,那么分辨率的宽和高分别除以2,占用的内存也会变小,最终图像的分辨率是103x103,占用内存为0.040470123M,bitmap大小整整缩小了4倍。

    (6)设置彩色模式
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    

    比较简单,只有一句话。

    图片.png

    ARGB_8888: 图像默认模式,有ARGB四个颜色通道,每个通道占8位。

    ARGB_4444: 已被弃用,有ARGB四个颜色通道,每个通道占4位。

    RGB_565: 屏幕默认颜色模式,有RGB三个颜色通道。

    ALPHA_8: 单通道,只有透明度通道。

    RGBA_F16HARDWARE是Android 8.0新增的,目前用的比较少。

    (7)获取图像的Mime类型
    options.outMimeType
    
    (8)设置缓冲区大小
    //设置缓存区,如果不设置默认为16M
    options.inTempStorage = new byte[1024 * 1024 * 16];
    

    如果不设置,那么默认为16M。

    (9)其他方法
    //这个值和抖动解码有关,默认值为false,表示不采用抖动解码。在Android N 之后已被废弃。
    options.inDither = true;
    
    //这个值表示是否在解码时图片有更高的品质,仅用于JPEG格式。如果设置为true,则图片会有更高的品质,但是会解码速度会很慢。
    //在Android N 之后已被废弃。
    options.inPreferQualityOverSpeed = true;
    
    //设置为true时,表示空间不够是否可以被释放。和inInputShareable一起使用。在Android5.0后被弃用。
    options.inPurgeable = false;
    
    //设置为true时,后者表示是否可以共享引用。和inPurgeable一起使用。在Android5.0后被弃用。
    options.inInputShareable = false;
    
    //在Android N 之后已被废弃
    options.mCancel = false;
    

    以上这些方法在高版本API上已被弃用,所以就不用研究了。

    相关文章

      网友评论

        本文标题:图片加载<第二篇>:BitmapFactory.Op

        本文链接:https://www.haomeiwen.com/subject/ksfzoqtx.html