图片学习程序猿

Android图片压缩以及优化

2017-06-05  本文已影响4843人  08_carmelo

前言

图片压缩在Android技术中已经属于烂大街,上周看了2个开源库然后对自己项目的压缩做了对比,发现一些新东西,记录与此。

为何要压缩

压缩原理

从上面可以总结出,图片压缩应该从两个方面入手同时进行:先是降低分辨率,然后降低每个像素的质量也就是内存占用。

分辨率压缩

假设有张原图是3840x2400,我想压缩成1920x1080,实际是不可能100%能压缩这个值的。因为图片压缩要保证宽高比,试想一下800x100的横向图可能压成20x200竖向图吗? 不可能的.。这里常见的算法就是在1920x1080的范围内保证较短边,然后按照比例压缩整个图:

这里原图的宽高比是 3840/2400 = 1.6,目标图的宽高比是1920/1080 = 1.78>1.6,较短边是高。所以就应该按照高的比例来压缩。
2400/1080=2.22,这样真实目标值就是:1728x1080,压缩比四舍五入是:2,然后通过下面代码进行压缩:

  private Bitmap compressPixel(String filePath){
    Bitmap bmp = null;
    BitmapFactory.Options options = new BitmapFactory.Options();
    //setting inSampleSize value allows to load a scaled down version of the original image
    options.inSampleSize = 2;

    //inJustDecodeBounds set to false to load the actual bitmap
    options.inJustDecodeBounds = false;
    options.inTempStorage = new byte[16 * 1024];
    try {
      //load the bitmap from its path
      bmp = BitmapFactory.decodeFile(filePath, options);
      if (bmp == null) {

        InputStream inputStream = null;
        try {
          inputStream = new FileInputStream(filePath);
          BitmapFactory.decodeStream(inputStream, null, options);
          inputStream.close();
        } catch (FileNotFoundException exception) {
          exception.printStackTrace();
        } catch (IOException exception) {
          exception.printStackTrace();
        }
      }
    } catch (OutOfMemoryError exception) {
      exception.printStackTrace();
    }finally {
      return bmp;
    }
  }

看起来没什么问题,看看实测结果,原图 3840*2400,大小2.2M,我选4个分辨率当做目标值来压缩:

image.png

可以看出压缩后的4张图没有一张达到目标值,而且偏差较大,原因就是options.inSampleSize这个属性,他只能是2的N次方,如果算出来是7,Android会取近似值8,以此类推导致这个值不能压缩到目标值。看了一下Compressor这个开源库他对此做了处理,把压缩后的图片在Canvas上面按照目标尺寸重绘,得到一个新的bitmap:

核心代码:

Matrix scaleMatrix = new Matrix();
    scaleMatrix.setScale(ratioX, ratioY, 0, 0);

    Canvas canvas = new Canvas(scaledBitmap);
    canvas.setMatrix(scaleMatrix);
    canvas.drawBitmap(bmp, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));

用Compressor开源库压缩的图片对比下:

image.png

可以看出每次都能压缩到真实目标值。(注意不是目标值,注意区分目标值和真实目标值)

质量压缩

Bitmap有个方法 compress(CompressFormat format, int quality, OutputStream stream),quality就是压缩质量传入0-100,数值越小压缩的越厉害。
不过我们一般不直接设置这个数值,而是自定义一个压缩后大小比如300KB,然后动态计算这个quality,核心代码:

//进行有损压缩ByteArrayOutputStream baos = new ByteArrayOutputStream();int options_ = 100;actualOutBitmap.compress(Bitmap.CompressFormat.JPEG, options_, baos);//质量压缩方法,把压缩后的数据存放到baos中 (100表示不压缩,0表示压缩到最小)int baosLength = baos.toByteArray().length;while (baosLength / 1024 > maxFileSize) {//循环判断如果压缩后图片是否大于maxMemmorrySize,大于继续压缩 baos.reset();//重置baos即让下一次的写入覆盖之前的内容 options_ = Math.max(0, options_ - 10);//图片质量每次减少10 actualOutBitmap.compress(Bitmap.CompressFormat.JPEG, options_, baos);//将压缩后的图片保存到baos中 baosLength = baos.toByteArray().length; if (options_ == 0)//如果图片的质量已降到最低则,不再进行压缩 break;}

压缩实践

image.png
上一篇 下一篇

猜你喜欢

热点阅读