- CompressUtil 流程图: 
 
CompressUtil 类 具体解释
public class CompressUtil {
/**
 * 终于封装的压缩方法
 * @param imgPath
 * @return
 */
public static Bitmap process(String imgPath){
    int degree = readPictureDegree(imgPath);    //获取旋转角度
    Bitmap bmp =getBmpByMaxSize(imgPath, 480);  //获取当前路径图片的位图,最大尺寸180*1024
    if (degree != 0) {
        bmp = rotaingImageView(degree, bmp);    //有旋转角度的旋转角度
    }
    return bmp;
}
/**
 * 读取图片属性:旋转的角度
 * @param path 图片绝对路径
 * @return degree旋转的角度
 */
@SuppressLint("NewApi")
public static int readPictureDegree(String path){
    int degree  = 0;    //设置默认图片角度为0度
    try {
        /**
         * Exif: 图像信息
         * Exif是一种图像文件格式。它的数据存储与JPEG格式是全然同样的。
         * 实际上Exif格式就是在JPEG格式头部插入了数码照片的信息。包含
         * 拍摄时的光圈、快门、白平衡、ISO、焦距、日期时间等各种和拍摄
         * 条件以及相机品牌、型号、色彩编码、拍摄时录制的声音以及GPS全
         * 球定位系统数据、缩略图等。
你能够利用不论什么能够查看JPEG文件的
         * 看图软件浏览Exif格式的照片,但并非全部的图形程序都能处理
         * Exif信息。
         *
         * ExifInterface:  图像信息接口类
         */
        /**
         * ExifInterface构造函数   ExifInterface(String filename)
         * 从指定的JPEG文件里读取EXIF标签。
         */
        //获取指定图片的图片处理对象
        ExifInterface exifInterface = new ExifInterface(path);
        /**
         * int <- getAttributeInt(String tag, int defaultValue)
         * 返回指定标记的整数值
         *
         * Attribute : 属性
         *
         * tag : 指标 (一共21个)
         * ExifInterface.TAG_APERTURE => 光圈指标
         * ExifInterface.TAG_DATETIME => 日期时间指标
         * ExifInterface.TAG_EXPOSURE_TIME => 公布时间指标
         * ExifInterface.TAG_FLASH => 闪光灯
         * ExifInterface.TAG_FOCAL_LENGTH => 焦距指标
         * ExifInterface.TAG_GPS_ALTITUDE => GPS海拔高度指标
         * ExifInterface.TAG_GPS_ALTITUDE_REF => GPS海拔參考点指标
         * ExifInterface.TAG_GPS_DATESTAMP => GPS日期戳指标
         * ExifInterface.TAG_GPS_LATITUDE => GPS纬度指标
         * ExifInterface.TAG_GPS_LATITUDE_REF => GPS纬度參考点指标
         * ExifInterface.TAG_GPS_LONGITUDE => GPS经度指标
         * ExifInterface.TAG_GPS_LONGITUDE_REF => GPS经度參考点指标
         * ExifInterface.TAG_GPS_PROCESSING_METHOD => GPS加工指标
         * ExifInterface.TAG_GPS_TIMESTAMP => GPS时间戳指标
         * ExifInterface.TAG_IMAGE_LENGTH => 图像长度指标
         * ExifInterface.TAG_IMAGE_WIDTH => 图像宽度指标
         * ExifInterface.TAG_ISO => 标签
         * ExifInterface.TAG_MAKE => 制作
         * ExifInterface.TAG_MODEL => 模型
         * ExifInterface.TAG_ORIENTATION => 定位指标
         * ExifInterface.TAG_WHITE_BALANCE => 白平衡指标
         *
         * defaultValue : 默认值 (一共11个)
         *
         * ExifInterface.ORIENTATION_FLIP_HORIZONTAL => 水平翻转
         * ExifInterface.ORIENTATION_FLIP_VERTICAL => 垂直翻转
         * ExifInterface.ORIENTATION_NORMAL => 正常
         * ExifInterface.ORIENTATION_ROTATE_180 => 旋转180度
         * ExifInterface.ORIENTATION_ROTATE_270 => 旋转270度
         * ExifInterface.ORIENTATION_ROTATE_90 => 旋转90度
         * ExifInterface.ORIENTATION_TRANSPOSE => 取向的转置
         * ExifInterface.ORIENTATION_TRANSVERSE => 方位横向
         * ExifInterface.ORIENTATION_UNDEFINED => 方向没有定义
         * ExifInterface.WHITEBALANCE_AUTO => 白平衡自己主动
         * ExifInterface.WHITEBALANCE_MANUAL => 手动白平衡
         */
        // 获取该图片的方向參数
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_ROTATE_90);
        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 (IOException e) {
        e.printStackTrace();
    }
    return degree;
}
/**
 * 旋转图片
 * @param angle
 * @param bitmap
 * @return Bitmap
 *
 * Bitmap : 位图
 * Bitmap是Android系统中的图像处理的最重要类之中的一个。
 * 用它能够获取图像文件信息。进行图像剪切、旋转、缩
 * 放等操作。并能够指定格式保存图像文件。
 *
 * Bitmap实如今android.graphics包中。
可是Bitmap
 * 类的构造函数是私有的,外面并不能实例化。仅仅能是通
 * 过JNI实例化。
这必定是 某个辅助类提供了创建Bitmap
 * 的接口,而这个类的实现通过JNI接口来实例化Bitmap的,
 * 这个类就是BitmapFactory。
 *
 * decode : 解码
 *
 * BitmapFactory.decodeFile(String pathName)
 * BitmapFactory.decodeFile(String pathName,Options opts)
 * BitmapFactory.decodeResource(Resource res,int id)
 * BitmapFactory.decodeResource(Resource res,int id,Options opts)
 *
 * 利用BitmapFactory能够从一个指定文件里,利用decodeFile()解出Bitmap;
 * 也能够定义的图片资源中,利用decodeResource()解出Bitmap
 *
 * 当中Options是decode时的选项
 * 在用法decodeFile()/decodeResource()时。都能够指定一个BitmapFacotry.Options。
 *
 * 利用Options的下列属性,能够指定decode的选项
 * inPreferredConfig => decode到内存中,手机中所採用的编码,可选值定义在Bitmap.Config中。缺省值是ARGB_8888
 * inJustDecodeBounds => 假设设置为true,并不会把图像的数据全然解码,亦即decodeXyz()返回值为null,可是Options的outAbc中解出了图像的基本信息
 * inSampleSize => 设置decode时的缩放比例
 *
 */
public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
    // Bitmap能够和Matrix结合实现图像的剪切、旋转、缩放等操作
    //获取Matrix对象
    Matrix matrix = new Matrix();
    //设置旋转角度
    matrix.postRotate(angle);
    // 创建新的图片
    Bitmap resizedBitmap=bitmap;
    /**
     * 用原Bitmap通过变换生成新的Bitmap的方法:
     *
     * public static Bitmap createBitmap(Bitmap source,int x,int y,int width,int height,Matrix m,boolean filter)
     * 这样的方法是终于的实现,后两种仅仅是对这样的方法的封装
     *
     * public static Bitmap createBitmap(Bitmap source,int x,int y,int width,int height)
     * 这样的方法能够从源Bitmap中指定区域(x,y, width, height)中挖出一块来实现剪切
     *
     * public static Bitmap createScaledBitmap(Bitmap src,int dstWidth,int dstHeight,boolean filter)
     * 这样的方法能够把源Bitmap缩放为dstWidth x dstHeight的Bitmap
     *
     * filter => 设为true => 对Bitmap进行滤波处理,会有抗锯齿的效果
     */
    try {
        resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        /**
         * Bitmap的recycle问题
         * recycle : 回收
         * 尽管Android有自己的垃圾回收机制,对于是不是要我们自己调用recycle。还的看情况而定。
         * 假设仅仅是使用少量的几张图片,回收与否关系不大。可是若有大量bitmap须要垃圾回收处理,
         * 那必定垃圾回收须要做的次数就很多其它也发生地更频繁。会对系统资源造成负荷。所以,这个时
         * 候还是自己试用recycle来释放的比較好。
         *
         * 注意 => 仅仅有当你确认你不会在使用这个bitmap的时候。就能够选择调用recycle()方法释放它。
         *
         */
        bitmap.recycle();
        //进行垃圾回收
        System.gc();
    }catch (OutOfMemoryError e){
        e.printStackTrace();
    }
    return resizedBitmap;
}
/**
 * 降低图片质量压缩
 * @param bmp
 * @param maxSize
 * @param fileSize
 * @return
 */
public static Bitmap compressBmp(Bitmap bmp, int maxSize, long fileSize) {
    Bitmap newBmp=bmp;
    //ByteArrayOutputStream => 捕获内存缓冲区的数据,转换成字节数组。
    ByteArrayOutputStream baos=null;
    //ByteArrayInputStream => 将字节数组转化为输入流
    ByteArrayInputStream bais=null;
    int quality = 100;
    if(fileSize>4*1024*1024){
        quality=40;
    }else if(fileSize>2*1024*1024){
        quality=50;
    }else if(fileSize>800*1024){
        quality=60;
    }
    try {
        /**
         * ByteArrayOutputStream类是在创建它的实例时,程序内部创建一个byte型别数组的缓冲区,
         * 然后利用ByteArrayOutputStream和ByteArrayInputStream的实例向数组中写入或读出
         * byte型数据。在网络传输中我们往往要传输非常多变量。我们能够利用ByteArrayOutputStream
         * 把全部的变量收集到一起。然后一次性把数据发送出去。
         */
        baos = new ByteArrayOutputStream();
        System.out.print("開始压缩: " + quality);
        /**
         * 图片压缩
         * Bitmap.compress(CompressFormat format, int quality, OutputStream stream)
         * 方法的參数format可设置JPEG或PNG格式;quality可选择压缩质量;fOut是输出流(OutputStream)
         */
        bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        float maxByte = maxSize * 1024;
        baos.flush();
        float scale = 1;
        while (baos.size() > maxByte) {
            System.out.print("压缩大小:" + baos.size() / 1024);
            System.out.print("压缩大小2:" + baos.toByteArray().length / 1024);
            scale = Math.round((float) baos.size() / maxByte);
            if (scale < 1) scale = 1;
            quality -= scale * 2;
            baos.reset();   //重置流,使流计数=0。
重置该流丢弃全部当前累积输出。
            bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);
            baos.flush();
        }
//            File file=new File(FileUtil.getAudioPath()+File.separator+System.currentTimeMillis()+”.jpg”); 
//            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file)); 
//            bos.write(baos.toByteArray()); 
//            bos.flush(); 
//            bos.close();
        System.out.print("压缩后大小:" + baos.size() / 1024);
        bais = new ByteArrayInputStream(baos.toByteArray());
        baos.flush();
        newBmp = BitmapFactory.decodeStream(bais);
        bmp.recycle();
        System.gc();
    }catch (OutOfMemoryError e){
        e.printStackTrace();
        //内存溢出则压缩很多其它
        if(!bmp.isRecycled()) {
            try {
                quality=quality/2;
                baos = new ByteArrayOutputStream();
                bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);
                bais = new ByteArrayInputStream(baos.toByteArray());
                baos.flush();
                newBmp = BitmapFactory.decodeStream(bais);
            }catch (Exception ex){}
        }
    }catch (Exception e){
        e.printStackTrace();
    }finally{
        try {
            if (bais != null) {
                bais.close();
            }
            if (baos != null) {
                baos.close();
            }
        }catch (Exception e){}
    }
    return newBmp;
}
public static Bitmap getBmpByMaxSize(String path, int maxSize){
    /**
     * Android使用BitmapFactory.Options解决载入大图片内存溢出问题
     *
     * 因为Android对图片使用内存有限制。若是载入几兆的大图片便内存溢出。
     * Bitmap会将图片的全部像素(即长x宽)载入到内存中,假设图片分辨率
     * 过大,会直接导致内存溢出(java.lang.OutOfMemoryError),仅仅有
     * 在BitmapFactory载入图片时使用BitmapFactory.Options对相关參
     * 数进行配置来降低载入的像素。
     *
     * BitmapFactory.Options这个类。有一个字段叫做 inJustDecodeBounds 。
     * 假设我们把它设为true。那么BitmapFactory.decodeFile(String path,
     * Options opt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽。高取回
     * 来给你,这样就不会占用太多的内存。也就不会那么频繁的发生OOM(Out Of
     * Memory)了。
     *
     */
    BitmapFactory.Options options=new BitmapFactory.Options();
    //使图片最小边框缩小到800像素
    options.inJustDecodeBounds=true;
    //这里返回的bitmap=null,但能够通过options.outWidth 和 options.outHeight就是我们想要的宽和高了
    BitmapFactory.decodeFile(path, options);
    //最短的永远都是宽度
    double width=options.outWidth<options.outHeight? options.outWidth: options.outHeight;
    //实际宽度/理想宽度 => 上传图片缩放比例
    int sampleSize=(int)Math.round(width/480);
    System.out.print("上传图片缩放比例:" + sampleSize);
    if(sampleSize<1) sampleSize=1;
    /**
     * inSampleSize表示缩略图大小为原始图片大小的几分之中的一个,
     * 即假设这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。
     */
    options.inSampleSize = sampleSize;
    options.inJustDecodeBounds=false;
    options.inDither=false;    /*不进行图片抖动处理*/
    options.inPreferredConfig=null;  /*设置让解码器以最佳方式解码*/
    /**
     * 以下两个字段须要组合使用  节约内存
     */
    options.inPurgeable = true; // 同意可清除
    options.inInputShareable = true;
    long length=new File(path).length();
    if(length>(1.5*1024*1024)){  //大于1.5M时
        options.inSampleSize+=(int)(length/1024/1024)*0.5; //当大于2M时为避免内存溢出缩小
    }
    Bitmap bitmap=null;
    try {
        bitmap = BitmapFactory.decodeFile(path, options);
    }catch (OutOfMemoryError e){
        e.printStackTrace();
        //内存溢出则将图片缩小一半
        if(options.inSampleSize<1) options.inSampleSize=1;
        options.inSampleSize=options.inSampleSize*2;
        bitmap=BitmapFactory.decodeFile(path, options);
    }
    if(length>(800*1024)) { //大于20K字节压缩
        bitmap = compressBmp(bitmap, maxSize, length);
    }
    return bitmap;
}
}