性能优化-Bitmap简单处理分析

来源:互联网 发布:淘宝网店的swot分析 编辑:程序博客网 时间:2024/06/01 10:37

BitmapFactory源码大致分析:

  • BitmapFactory有一个静态内部类Options,有以下属性:
inBitmap:在解析Bitmap时重用该Bitmap,不过必须等大的Bitmap而且inMutable须为trueinPreferredConfig:Bitmap.Config.ARGB_8888等inMutable:配置Bitmap是否可以更改,比如:在Bitmap上隔几个像素加一条线段inJustDecodeBounds:为true仅返回Bitmap的宽高等属性inSampleSize:须=1,表示Bitmap的压缩比例,如:inSampleSize=4,将返回一个是原始图的1/16大小的BitmapinDither:是否抖动,默认为falseinPremultiplied:默认为true,一般不改变它的值inDensity:Bitmap的像素密度inTargetDensity:Bitmap最终的像素密度inScreenDensity:当前屏幕的像素密度inScaled:是否支持缩放,默认为true,当设置了这个,Bitmap将会以inTargetDensity的值进行缩放inPurgeable:当存储Pixel的内存空间在系统内存不足时是否可以被回收inInputShareable:inPurgeable为true情况下才生效,是否可以共享一个InputStreaminPreferQualityOverSpeed:为true则优先保证Bitmap质量其次是解码速度outWidth:返回的Bitmap的宽outHeight:返回的Bitmap的高inTempStorage:解码时的临时空间,建议16*1024
  • BitmapFactory中重要的方法:

    Bitmap decodeFile(String pathName)
    Bitmap decodeFile(String pathName, Options opts)
    Bitmap decodeResource(…)
    Bitmap decodeByteArray(…)
    Bitmap decodeStream(…)
    Bitmap decodeFileDescriptor(…)

    其实最终还是调用decodeStream(…)来加载图片,而decodeStream(…)则是调用native方法。而在调用decodeResource在解析时还会多调用一个方法:

public static Bitmap decodeResourceStream(Resources res, TypedValue value,            InputStream is, Rect pad, Options opts) {        if (opts == null) {            opts = new Options();        }        if (opts.inDensity == 0 && value != null) {            final int density = value.density;            if (density == TypedValue.DENSITY_DEFAULT) {                opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;            } else if (density != TypedValue.DENSITY_NONE) {                opts.inDensity = density;            }        }        if (opts.inTargetDensity == 0 && res != null) {            opts.inTargetDensity = res.getDisplayMetrics().densityDpi;        }        return decodeStream(is, pad, opts);    }

它主要是对Options进行处理了,在得到 opts.inDensity 属性的前提下,如果我们没有对该属性设定值,那么将
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
赋定这个默认的Density值,这个默认值为160,为标准的dpi比例,即在Density=160的设备上1dp=1px,
还有这么一行
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
对 opts.inTargetDensity 进行了赋值,该值为当前设备的densityDpi值,所以说在decodeResourceStream方法中主要两件事事:

  1. 对opts.inDensity赋值,没有则赋默认值160、
  2. 对opts.inTargetDensity赋值,没有则赋当前设备的densityDpi值

重点来了,之后参数将传入decodeStream方法,该方法中在调用native方法进行解析Bitmap后会调用这个方法
setDensityFromOptions(bm, opts);
该方法主要就是把刚刚赋值过的两个属性inDensity和inTargetDensity给Bitmap进行赋值,不过并不是直接赋给Bitmap就完了,中间有个判断,当inDensity的值与inTargetDensity或与设备的屏幕Density不相等时,则将应用inTargetDensity的值,如果相等则应用inDensity的值。
所以总结来说, setDensityFromOptions 方法就是把 inTargetDensity 的值赋给Bitmap,不过前提是opts.inScaled = true;
进过上面的分析,可以得出这样一个结论:

  • 在不配置Options的情况下:
    1. decodeFile、decodeStream在解析时不会对Bitmap进行一系列的屏幕适配,解析出来的将是原始大小的图
    2. decodeResource在解析时会对Bitmap根据当前设备屏幕像素密度densityDpi的值进行缩放适配操作,使得解析出来的Bitmap与当前设备的分辨率匹配,达到一个最佳的显示效果,并且Bitmap的大小将比原始的大。

下面简单介绍几种压缩方式:

  • 质量压缩
    /**     * 原理:通过算法抠掉(同化)了图片中的一些某个些点附近相近的像素,     * 达到降低质量介绍文件大小的目的。     * 减小了图片质量     *      * 注意:它其实只能实现对file的影响,     * 对加载这个图片出来的bitmap内存是无法节省的,还是那么大。     * 也就是width*height,对于质量压缩,     * 并不会改变图片的真实的像素(像素大小不会变)。     *      * 使用场景:将图片压缩后保存到本地,或者将图片上传到服务器。根据实际需求来。     */    public void qualitCompress(){        BitmapFactory.Options options = new BitmapFactory.Options();        Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);        //压缩图片        compressImageToFile(bitmap, new File(sdFile,"qualityCompress.jpeg"));    }    public static void compressImageToFile(Bitmap bmp,File file){        //0~100   越大代表压缩的越少        int quality = 50;        ByteArrayOutputStream baos = new ByteArrayOutputStream();        bmp.compress(Bitmap.CompressFormat.JPEG, quality , baos );        try {            FileOutputStream fos = new FileOutputStream(file);            fos.write(baos.toByteArray());            fos.flush();            fos.close();        } catch (Exception e) {            e.printStackTrace();        }    }
  • 尺寸压缩
    /**     * 通过减少单位尺寸的像素值,正真意义上的降低像素。     * 使用场景:缓存缩略图的时候(头像处理)     */    public void sizeCompress(View v){        BitmapFactory.Options options = new BitmapFactory.Options();        Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);        compressBitmapToFileBySize(bitmap, new File(sdFile,"sizeCompress.jpeg"));    }    public static void compressBitmapToFileBySize(Bitmap bmp,File file){        //压缩尺寸倍数,值越大,图片的尺寸就越小        int ratio = 4;        Bitmap result = Bitmap.createBitmap(bmp.getWidth()/ratio, bmp.getHeight()/ratio, Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(result);        //这里举例        RectF rect = new RectF(0, 0, bmp.getWidth()/ratio, bmp.getHeight()/ratio);        canvas.drawBitmap(bmp, null, rect , null);        ByteArrayOutputStream baos = new ByteArrayOutputStream();        result.compress(Bitmap.CompressFormat.JPEG, 100, baos);        try {            FileOutputStream fos = new FileOutputStream(file);            fos.write(baos.toByteArray());            fos.flush();            fos.close();        } catch (Exception e) {            e.printStackTrace();        }    }
  • 采样率压缩
        /**         * 设置图片的采样率,降低图片像素         * @param filePath         * @param file         */        public static void compressBitmap(String filePath, File file){            // 数值越高,图片像素越低            int inSampleSize = 8;            BitmapFactory.Options options = new BitmapFactory.Options();            options.inJustDecodeBounds = false;//          options.inJustDecodeBounds = true;//为true的时候不会真正加载图片,而是得到图片的宽高信息。            //采样率            options.inSampleSize = inSampleSize;            Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);            ByteArrayOutputStream baos = new ByteArrayOutputStream();            // 把压缩后的数据存放到baos中            bitmap.compress(Bitmap.CompressFormat.JPEG, 100 ,baos);            try {                if(file.exists())                {                    file.delete();                }                else {                    file.createNewFile();                }                FileOutputStream fos = new FileOutputStream(file);                fos.write(baos.toByteArray());                fos.flush();                fos.close();            } catch (Exception e) {                e.printStackTrace();            }        }
0 0