Android图片压缩优化,解决内存溢出问题

Android中有多种图片压缩的方式,如质量压缩、采样率压缩、RGB565压缩、尺寸缩放压缩等

Android图片主以bitmap形式存在,其内存大小的计算公式为:图片宽度×图片高度×一个像素点所占字节数

所以减小这三个参数的任一参数都可减小bitmap所占的内存大小

一、质量压缩

保持图片像素的前提下改变图片的位深及透明度

该方法使用的是bitmap.compress(Bitmap.CompressFormat format, int quality, OutputStream stream),该方法是将位图的压缩版本写入指定的输出流。第一个参数为图片压缩格式,有CompressFormat .PNG、CompressFormat .JPEG等,需注意的是这里的PNG图片为无损的,是无法压缩的;第二个参数quality就为压缩数,设置为0-100之间,参数为100时不对图片压缩;第三个参数为输出流,位图的压缩版本就是写入该流中。

    private byte[] bitmapCompress(Bitmap bitmap){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int quality = 100;
        //循环判断如果压缩后图片是否大于100kb,大于继续压缩,这里的要求数值可根据需求设置
        while ( baos.toByteArray().length / 1024>1000) { 
            //重置baos即清空baos
            baos.reset();
            //这里压缩quality%,把压缩后的数据存放到baos中
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
            quality -= 10;//每次都减少10
        }
        //转为字节数组返回
        byte[] bytes = baos.toByteArray(); 
        return bytes;
    }

 若通过BitmapFactory.decodeByteArray(bytes,0,bytes.length)重新获得一个bitmap,你会发现bitmap和原来的还是一样大小并没有压缩,因为该方法压缩并没有改变bitmap内存计算公式中的任何一个参数,所以大小是没有改变的,但是打印bytes.length()你会发现大小会根据quality的变小而变小。我理解的是虽然该方法没有将bitmap内存占用变小,但是bytes.length()变小可用来作二进制图片传输,如微信分享等。

二、采样率压缩

设置图片的采样率,降低图片像素

该方法是通过设置BitmapFactory.Options中的inJustDecodeBounds来压缩图片,如果设置该值>1,请求解码器对原始图像进行子采样,返回较小的图像以保存内存。

    private Bitmap sampleCompress(String path){
        BitmapFactory.Options options = new BitmapFactory.Options();
        //该参数设为true,则获取时bitmap返回为空,避免bitmap内存分配
        options.inJustDecodeBounds = true;  
        //获取bitmap参数信息
        BitmapFactory.decodeFile(path,options); 
        int inSampleSize = 1;
        //循环判断如果压缩后图片是否大于1024kb,大于继续压缩,这里的要求数值可根据需求设置
        while (getImageMemory(options.outWidth, options.outHeight, inSampleSize) > 1024) {
            inSampleSize += 1;
        }
        //将参数设为false,则获取时bitmap返回不为空
        options.inJustDecodeBounds = false; 
        options.inSampleSize = inSampleSize;
        return BitmapFactory.decodeFile(path,options);
    }
    //24位位图内存大小计算
    private static int getImageMemory(int width, int height, int inSampleSize) {
        //bitmap内存计算公式
        return (width / inSampleSize) * (height / inSampleSize) * 3 / 1024; 
    }

设置inSampleSize的值,该值为int类型,假如设为2,则宽和高都为原来的1/2,宽高都减少了,根据计算公式则bitmap占用内存也就自然减小了。BMP文件的图像深度可选lbit、4bit、8bit及24bit。

如果图片大小是800*600的位图,8位,则这个位图所占空间为:800*600*8/(8*1024*1024)=0.457M
图片大小是800*600的位图,24位,则这个位图所占空间为 800*600*24/(8*1024*1024)=1.37M

三、RGB565压缩

改变一个像素点占用字节数

其中,A代表透明度;R代表红色;G代表绿色;B代表蓝色。

ALPHA_8        表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度 
ARGB_4444    表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节 
ARGB_8888    表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节 
RGB_565        表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节

    private Bitmap argbCompress(String path){
        BitmapFactory.Options options = new BitmapFactory.Options();
        //如果这是非空的,解码器将尝试解码到这个颜色空间中。原图为ARGB_8888,设置其为RGB_565
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeFile(path,options);
    }

最后得到的图片内存占用为原来图片大小的一半 ,长度和宽度没发生变化。RGB_565对不要求透明度的图来说视觉影像不大。

四、尺寸缩放压缩

改变图片尺寸大小,缩小图片所占内存

该方法通过bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)来改变图片尺寸。第一个参数为资源bitmap;第二个参数为目标宽度;第三个参数为目标高度,第四个参数为过滤器,如果源应该被过滤,则为true。

Bitmap bm = bitmap.createScaledBitmap(bitmap,100,100,true);

所得到的bm比原来的bitmap内存小了,因为尺寸变小了,变成了期望的100*100。

猜你喜欢

转载自blog.csdn.net/qq_40861368/article/details/81536487