Android 高级工程师进阶 ~ 网易云课堂 学习笔记

学会图片终极压缩,快速处理项目中的复杂业务

【直播主题】

Android黑科技,图片终极压缩

【直播大纲】
1、浅谈Luban图片压缩框架,开启造轮子之路
2、详解架构思路和像素压缩、质量压缩的核心原理
3、项目中的复杂业务该如何处理

戳此链接占座:https://url.163.com/rKN

Android 黑科技:图片终极压缩
支持自定义配置、不 失真和批量处理

图片上传为什么要压缩?

能否直接上传原图。让后台处理?

图片服务器的磁盘空间非常昂贵

尽可能避免Android OOM异常

后台约定的规则,比如 每张图片必须<=300Kb

图片压缩流程

1,递归每张图片
2,设置图片格式
3,质量压缩
4,像素修复
5,返回压缩结果集
6,完成压缩

图片压缩方式

设置图片格式

Android 目前常用的图片格式有 png jpeg 和 webp Bitmap.CompressFormat.JPEG

质量压缩

根据width * height 一个像素的所 占用的字节数 计算,宽高不变 bitmap.compress(format,quality,baos)
由于png 是无损压缩,所以设置 quality无效(不适合作为缩略图)

采样率压缩

缩小图片分辨率,减少所占用磁盘空间和内存大小 BitmapFactory.Options.inSampleSize

缩放压缩

减少图片的像素,降低所占用磁盘空间大小和内存大小 canvas.drawBitmap(bitmap,null,rectF,null)

JNI 调用JPEG库

Android 的图片引擎使用的是阉割版的skia 引擎,去掉了图片压缩中的哈夫曼算法

图片压缩开源框架

https://github.com/Curzibn/Luban

https://github.com/zetbaitsu/Compressor

Luban 框架缺点

1,当没有设定压缩路径时,抛异常无闪退
2,源码中,压缩比率固定住60,无法修改
3,压缩配置,参数不太适应真实项目需求
4,不能指定压缩大小,比如100kb 以内

图片压缩核心代码

  /**     * 压缩文件到Bitmap     *     * @param filePath 图片文件地址     * @param quality  要压缩的质量     * @return     */    public static Bitmap getSmallBitmap(String filePath, int quality) {        final BitmapFactory.Options options = new BitmapFactory.Options();        options.inJustDecodeBounds = true;        BitmapFactory.decodeFile(filePath, options);        //计算采样,现在主流手机比较多是800*480 分辨率        options.inSampleSize = calculateInSampleSize(options, 480, 800);        //用样本大小集解码位图        options.inJustDecodeBounds = false;        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);        if (bitmap == null) {            return null;        }        //读取图片角度        int degree = readPitcureDegree(filePath);        //旋转位图        bitmap = rotateBitmap(bitmap, degree);        ByteArrayOutputStream baos = null;        try {            baos = new ByteArrayOutputStream();            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);        } finally {            try {                if (baos != null) {                    baos.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        return bitmap;    }    private static Bitmap rotateBitmap(Bitmap bitmap, int rotate) {        if (bitmap == null)            return null;        int w = bitmap.getWidth();        int h = bitmap.getHeight();        Matrix matrix = new Matrix();        matrix.postRotate(rotate);        return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);    }    private static int readPitcureDegree(String path) {        int degree = 0;        try {            ExifInterface exifInterface = new ExifInterface(path);            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);            switch (orientation) {                case ExifInterface.ORIENTATION_ROTATE_90:                    degree = 90;                    break;                case ExifInterface.ORIENTATION_ROTATE_180:                    degree = 180;                    break;                case ExifInterface.ORIENTATION_ROTATE_270:                    degree = 270;                    break;            }        } catch (Exception e) {            e.printStackTrace();        }        return degree;    }    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {        final int height = options.outHeight;        final int width = options.outWidth;        int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {            final int heightRatio = Math.round((float) height / (float) reqHeight);            final int widthRatio = Math.round((float) width / (float) reqWidth);            inSampleSize = heightRatio < widthRatio ? widthRatio : heightRatio;        }        return inSampleSize;    }    /**     * 按大小压缩     *     * @return     */    private Bitmap getImage(String srcpath) {        BitmapFactory.Options newOpts = new BitmapFactory.Options();        //开始读入图片,此时 把 options.inJustDecodeBounds 设回 true了        newOpts.inJustDecodeBounds = true;        Bitmap bitmap;        newOpts.inJustDecodeBounds = false;        int w = newOpts.outWidth;        int h = newOpts.outHeight;        //现在主流手机比较多是800*480 分辨率 所以高和宽我们设置为        float hh = 800f;//这里设置高度为800f        float ww = 480f;// 这里设置宽度为480f        //缩放比,由于是固定比例缩放,只用高或宽其中一个数据进行计算即可        int 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);        return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩    }    /**     * 质量压缩     *     * @param image     * @return     */    private Bitmap compressImage(Bitmap image) {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        //质量压缩方法,这里100 表示不压缩 把压缩后的数据存放到 baos 中        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);        int options = 100;        while (baos.toByteArray().length / 1024 > 100) {//循环判断 如果压缩图片师范大于100kb,大于继续压缩            baos.reset();//重置 baos 即清空 baos            image.compress(Bitmap.CompressFormat.JPEG, options, baos); //这里压缩 options 把压缩后的数据存放到 baos 中            options -= 10;        }        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据存放到 ByteArrayInputStream        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream 数据生成图片        return bitmap;    }

源码

https://github.com/yoyo0316/StudyDemo/commit/8c22a4ff4eebd0142e9c2a604bed94003bf2e974

更多相关文章

  1. Android(安卓)matrix 控制图片的旋转、缩放、移动
  2. android拍照与读取相册
  3. Android(安卓)报错:Caused by: android.os.FileUriExposedExcepti
  4. android解决坚屏拍照和保存图片旋转90度的问题,并兼容4.0
  5. [Android]在App中使用相机
  6. android WebView 图片缩放功能小结
  7. Android(安卓)主流图片库Picasso Glide Fresco对比分析
  8. android背景选择器selector用法汇总
  9. ImageView的scaletype属性

随机推荐

  1. Android(安卓)资料总结(全)
  2. Android更新Ui的几种方法和见解
  3. android 的一些小知识
  4. [android]EditText的一些设置
  5. 【安卓学习之开发工具】 Android(安卓)St
  6. Android开发实战-项目学习笔记(2)
  7. Android开发实例大全
  8. Android有用代码片段(四)
  9. Android(安卓)打包
  10. 【Android布局】在程序中设置android:gra