Android详解图片压缩问题

今天就来聊一聊Android中图片压缩的问题,Android中图片以Bitmap位图来占用内存,要想知道图片压缩,就得先知道Bitmap是如何占用内存的,下面就一步一步来讲解。


Bitmap占用内存大小 = 图片宽 * 图片高 * 图片每个像素所占用的字节数。


图片的宽高我们都知道,可是每个像素所占用的字节数什么鬼?Android中图片的压缩格式一般有一下几种:


ARGB_8888:分别代表Alpha透明的、Red、Green、Blue,后面四个8表示ARGB分别占8位,也就是4个字节,那么最终就可以理解为ARGB_8888格式的图片每个像素占用4个字节。

ARGB_4444:跟ARGB_8888相似,只不过每个占用4位,也就是2个字节(因为太模糊现在基本不用ARGB_4444格式图片)。

RGB_565:分别代表Red、Green、Blue,同样后面565代表RGB跟别占5、6、5位,也就是2个字节。

ALPHA_8:表示一个像素占8位,一个字节,没有颜色,只有透明的。


好了,上面我们大致介绍了Android中图片的几种压缩格式,其实Andorid默认的图片压缩格式是ARGB_8888,下面我们来看看,一张ARGB_8888的图片占用的内存,我随便网上下了一张图片,存在assets文件夹中读取出来,避免存在hdpi,xhdpi等,他们会默认缩放图片大小,再此不做详细赘述。


   

上图左边的是图片占用的内存字节数,右边是这张图片的宽高,默认ARGB_8888。1000 * 666 * 4=?,不就是2664000字节么。既然知道bitmap在内存中怎么占用内存了,下面就开始介绍图片压缩方法:


1、质量压缩


public static Bitmap compressImage(Bitmap image) {

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    //质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos    image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    int options = 100;
    //循环判断如果压缩后图片是否大于300kb,小于继续压缩
    while ( baos.toByteArray().length / 1024 > 300) {
        baos.reset();//重置baos即清空baos
        //这里压缩options%,把压缩后的数据存放到baos        image.compress(Bitmap.CompressFormat.JPEG, options, baos);
        options -= 10;//每次都减少10
    }
    //把压缩后的数据baos存放到ByteArrayInputStream    ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
    //ByteArrayInputStream数据生成图片
    Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);

    return bitmap;
}

上面这段代码的大致意思就是先构建一个字节数组输出流,自带缓冲区,先利用compress方法将bitmap位图读到缓冲区中,然后判断缓冲区中的内容字节数/1024也就是KB,是否大于300K,如果大于300的话则清除掉缓冲区的内容,继续按照压缩比例options读入缓冲区中,如此循环直到图片不大于300K则退出循环,返回Bitmap对象。其实关键就是通过设置options的大小来压缩图片,options取值是0-100,100表示不压缩。



上图是我打印的options的取值0-100个别数字,得到的结果确是占用的内存空间一样多的字节,没压缩啊感觉,为什么呢?解释一下,因为android所谓的质量压缩,它其实是压缩了图片的深度跟透明度,图片的宽高跟像素并没有改变,所以它所占用的内存空间并没有改变,但是质量压缩后的图片导出到手机本地会发现文件变小了,所以说android中质量压缩不适用于app浏览显示高清大图,个人感觉适用于上传给服务器批量大图文件,可以先利用质量压缩将压缩后的图片存储到本地,然后上传本地图片至服务器。这里顺便提下一下各位读者,质量压缩无法压缩png图片,因为png图片就是无损的,不能进行质量压缩。


2、采样率压缩



public static Bitmap compressImage(String srcPath) {
   BitmapFactory.Options newOpts = new BitmapFactory.Options();
   //开始读入图片,此时把options.inJustDecodeBounds 设回true   newOpts.inJustDecodeBounds = true;
   Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//此时返回bm为空
   newOpts.inJustDecodeBounds = false;
   int w = newOpts.outWidth;
   int h = newOpts.outHeight;
   float hh = 800;//这里设置高度为1280f
   float ww = 400f;//这里设置宽度为720f
   //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
   int be = 1;//be=1表示不缩放
   if (w >= h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
      be = (int) (newOpts.outWidth / ww);
   } else if (w <= h && h > hh) {//如果高度高的话根据宽度固定大小缩放
      be = (int) (newOpts.outHeight / hh);
   }
   if (be <= 0)
      be = 1;
   newOpts.inSampleSize = be;//设置缩放比例
   //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false   bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
   if(bitmap == null){
      return null;
   }
   bitmap = BitmapUtil.rotateBitmap(srcPath, bitmap);
   return bitmap;
}

上述代码的





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值