Android 图片压缩

最近重新学习图片压缩,网上各种找资料,对比,总结,感觉有些理解了,总结一下。
在android中,图片的加载一般是把图片转化为Bitmap,设置到ImageView中显示出来。这里有个问题需要特别注意,也是我写下这篇记录的原因所在:当图片以Bitmap形式存在时,它占用的内存大小的计算方式:
memory=图片宽度(px)* 图片高度(px)* 单位像素占用字节数。

单位像素占用字节数就是图片的色彩模式,ARGB(透明度、红色、绿色、蓝色)常见的有:
ARGB_4444:单位像素所占字节数:2。argb各站4位,4*4/8=2(字节)。

ARGB_8888:单位像素所占字节数:4。argb各站8位,8*4/8=4(字节)。android默认格式。
RGB_565:单位像素所占字节数:2。

例:我手机上有张照片是:2320*4128,大小是3.1MB,要1:1显示出来的话,需要的内存是:2320*4128*4/1024/1024=36.53MB,好吧,我确定显示图片的时候必须要考虑压缩了。手机分辨率为1280*720,铺满全屏时,需要1280*720*4/1024/1024=3.52MB。很多时候,并不需要显示全屏的图片,仅仅只需要显示一张缩略图就够了。比如一排显示6张100*120的图片,需要的内存是100*120*4/1024*6=281.25KB,再添加一个缓存的功能,应用的流畅性大大提高。

接下来进入正题,压缩。
压缩主要分为2部分,尺寸压缩和质量压缩。
1.尺寸压缩
即压缩图片的像素大小。上代码:

 /**
     * 从数组得到图片
     * @param b  图片
     * @param width  指定的宽
     * @param height 指定的高
     * @return bitmap
     */
    public static Bitmap compressBitmapFromByte(byte [] b,int width,int height){
        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        BitmapFactory.decodeByteArray(b, 0, b.length,options);
        options.inSampleSize=getInSampleSize(options,width,height);
        options.inJustDecodeBounds=false;
        Bitmap bitmap=BitmapFactory.decodeByteArray(b,0,b.length,options);
        return  createScaledBitmap(bitmap,width,height);
    }

    /**
     * 从内存中加载图片
     * @param path 路径
     * @param width 显示的宽
     * @param height 显示的高
     * @return bitmap
     */
    public static Bitmap compressBitmapFromSD(String path,int width,int height){
        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        BitmapFactory.decodeFile(path,options);
        options.inSampleSize=getInSampleSize(options,width,height);
        options.inJustDecodeBounds=false;
        Bitmap bitmap=BitmapFactory.decodeFile(path,options);
        return createScaledBitmap(bitmap,width,height);
    }

    /**
     * 得到压缩倍数 一般为2的N次幂倍
     */
    private static int getInSampleSize(BitmapFactory.Options options,int width,int height){
        int w=options.outWidth;
        int h=options.outHeight;
        int be=1;
        if (w>width||h>height) {
            int hh=w/2;
            int ww=w/2;
            while ((hh/be)>height&&(ww/be)>width){
                be*=2;
            }
        }
        return be;
    }

    /**
     * 通过Bitmap.createScaledBitmap方法决定是否需要回收bm
     */
    private static Bitmap createScaledBitmap(Bitmap bm,int w,int h){
        // 如果放大图片,filter决定是否平滑,如果缩小图片,filter无影响
        Bitmap bitmap=Bitmap.createScaledBitmap(bm,w,h,false);
        if (bitmap!=bm){//如果没有缩放,不用回收
            bm.recycle();
        }
        return  bitmap;
    }

其中需要注意的地方是options.inJustDecodeBounds=true;设置以后,程序可以读取到图片的宽高,而不需要吧图片完全读取近内存,能有效避免内存溢出的发生,options.inJustDecodeBounds=false设置后,正式将图片读入内存,进行压缩。bitmap很占内存,推荐在需要的时候主动回收。

2.质量压缩
现在的照片很多都有2M以上,我们上传的时候并不需要这么大,可以适当压缩大小后上传。

 /**
     * 压缩质量
     * @param image Bitmap
     * @param size 指定大小
     * @return Bitmap
     */
    public static Bitmap compressImage(Bitmap image,int size) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 90;
        while (baos.toByteArray().length / 1024 > size) { // 循环判断如果压缩后图片是否大于size,大于继续压缩
            baos.reset();// 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
            options -= 10;
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
        return BitmapFactory.decodeStream(isBm, null, null);
    }

这是我用过的压缩方法,把一张高清大图压缩成指定大小和尺寸的图片文件(不是精确值)

/**
     * 得到压缩后的图片File
     * @param path 需要压缩的图片路径
     * @param filepath  压所得到的图片的储存路径
     * @return File
     */
    public static File getCompressFile(String path, String filepath,int width,int height,int size){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        options.inJustDecodeBounds = false;
        options.inSampleSize = getInSampleSize(options,width,height);
        Bitmap bitmap = BitmapFactory.decodeFile(path, options);
        return getCompressPic(bitmap,filepath,size);
    }

    /**
     * 把Bitmap压缩到指定文件夹下
     * @param bitmap bitmap
     * @param filepath 压所得到的图片的储存路径
     * @return
     */
    public static File getCompressPic(Bitmap bitmap,String filepath,int size){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 90;
        while (baos.toByteArray().length/ 1024 > size) {
            baos.reset();
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
            options -= 10;
        }
        File file=new File(filepath);
        if (!file.exists()) file.mkdirs();
        String picName=System.currentTimeMillis()+".jpg";
        File file2=new File(file,picName);
        try {
            FileOutputStream out=new FileOutputStream(file2);
            out.write(baos.toByteArray());
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return file2;
        } catch (IOException e) {
            e.printStackTrace();
            return file2;
        }
        return file2;
    }

图片压缩差不多就这些,以后想到更好的在补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值