content: package com.lzy.imagepicker.view;
  
  import android.content.Context;
  import android.content.res.TypedArray;
  import android.graphics.Bitmap;
  import android.graphics.BitmapShader;
  import android.graphics.Canvas;
  import android.graphics.Matrix;
  import android.graphics.Paint;
  import android.graphics.Path;
  import android.graphics.PointF;
  import android.graphics.RectF;
  import android.graphics.Region;
  import android.graphics.Shader;
  import android.graphics.drawable.BitmapDrawable;
  import android.graphics.drawable.Drawable;
  import android.net.Uri;
  import android.os.Handler;
  import android.os.Looper;
  import android.os.Message;
  import android.support.v4.view.ViewCompat;
  import android.util.AttributeSet;
  import android.util.TypedValue;
  import android.view.MotionEvent;
  import android.widget.ImageView;
  
  import com.lzy.imagepicker.R;
  
  import java.io.File;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Locale;
  
  /**
   * ================================================
   * 作    者：廖子尧
   * 版    本：1.0
   * 创建日期：2016/1/7
   * 描    述：
   * Matrix 的9个值分别为  缩放  平移  倾斜
   * MSCALE_X	 MSKEW_X	MTRANS_X
   * MSKEW_Y	 MSCALE_Y	MTRANS_Y
   * MPERSP_0  MPERSP_1	MPERSP_2
   * 修订历史：
   * ================================================
   */
  
  public class CropImageView extends ImageView {
  
      /******************************** 中间的FocusView绘图相关的参数 *****************************/
      public enum Style {
          RECTANGLE, CIRCLE
      }
  
      private Style[] styles = {Style.RECTANGLE, Style.CIRCLE};
  
      private int mMaskColor = 0xAF000000;   //暗色
      private int mBorderColor = 0xAA808080; //焦点框的边框颜色
      private int mBorderWidth = 1;         //焦点边框的宽度（画笔宽度）
      private int mFocusWidth = 250;         //焦点框的宽度
      private int mFocusHeight = 250;        //焦点框的高度
      private int mDefaultStyleIndex = 0;    //默认焦点框的形状
  
      private Style mStyle = styles[mDefaultStyleIndex];
      private Paint mBorderPaint = new Paint();
      private Path mFocusPath = new Path();
      private RectF mFocusRect = new RectF();
  
      /******************************** 图片缩放位移控制的参数 ************************************/
      private static final float MAX_SCALE = 4.0f;  //最大缩放比，图片缩放后的大小与中间选中区域的比值
      private static final int NONE = 0;   // 初始化
      private static final int DRAG = 1;   // 拖拽
      private static final int ZOOM = 2;   // 缩放
      private static final int ROTATE = 3; // 旋转
      private static final int ZOOM_OR_ROTATE = 4;  // 缩放或旋转
  
      private static final int SAVE_SUCCESS = 1001;  // 缩放或旋转
      private static final int SAVE_ERROR = 1002;  // 缩放或旋转
  
      private int mImageWidth;
      private int mImageHeight;
      private int mRotatedImageWidth;
      private int mRotatedImageHeight;
      private Matrix matrix = new Matrix();      //图片变换的matrix
      private Matrix savedMatrix = new Matrix(); //开始变幻的时候，图片的matrix
      private PointF pA = new PointF();          //第一个手指按下点的坐标
      private PointF pB = new PointF();          //第二个手指按下点的坐标
      private PointF midPoint = new PointF();    //两个手指的中间点
      private PointF doubleClickPos = new PointF();  //双击图片的时候，双击点的坐标
      private PointF mFocusMidPoint = new PointF();  //中间View的中间点
      private int mode = NONE;            //初始的模式
      private long doubleClickTime = 0;   //第二次双击的时间
      private double rotation = 0;        //手指旋转的角度，不是90的整数倍，可能为任意值，需要转换成level
      private float oldDist = 1;          //双指第一次的距离
      private int sumRotateLevel = 0;     //旋转的角度，90的整数倍
      private float mMaxScale = MAX_SCALE;//程序根据不同图片的大小，动态得到的最大缩放比
      private boolean isInited = false;   //是否经过了 onSizeChanged 初始化
      private boolean mSaving = false;    //是否正在保存
      private static Handler mHandler = new InnerHandler();
  
      public CropImageView(Context context) {
          this(context, null);
      }
  
      public CropImageView(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public CropImageView(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
          mFocusWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mFocusWidth, getResources().getDisplayMetrics());
          mFocusHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mFocusHeight, getResources().getDisplayMetrics());
          mBorderWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mBorderWidth, getResources().getDisplayMetrics());
  
          TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CropImageView);
          mMaskColor = a.getColor(R.styleable.CropImageView_cropMaskColor, mMaskColor);
          mBorderColor = a.getColor(R.styleable.CropImageView_cropBorderColor, mBorderColor);
          mBorderWidth = a.getDimensionPixelSize(R.styleable.CropImageView_cropBorderWidth, mBorderWidth);
          mFocusWidth = a.getDimensionPixelSize(R.styleable.CropImageView_cropFocusWidth, mFocusWidth);
          mFocusHeight = a.getDimensionPixelSize(R.styleable.CropImageView_cropFocusHeight, mFocusHeight);
          mDefaultStyleIndex = a.getInteger(R.styleable.CropImageView_cropStyle, mDefaultStyleIndex);
          mStyle = styles[mDefaultStyleIndex];
          a.recycle();
  
          //只允许图片为当前的缩放模式
          setScaleType(ScaleType.MATRIX);
      }
  
      @Override
      public void setImageBitmap(Bitmap bm) {
          super.setImageBitmap(bm);
          initImage();
      }
  
      @Override
      public void setImageDrawable(Drawable drawable) {
          super.setImageDrawable(drawable);
          initImage();
      }
  
      @Override
      public void setImageResource(int resId) {
          super.setImageResource(resId);
          initImage();
      }
  
      @Override
      public void setImageURI(Uri uri) {
          super.setImageURI(uri);
          initImage();
      }
  
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh) {
          super.onSizeChanged(w, h, oldw, oldh);
          isInited = true;
          initImage();
      }
  
      /** 初始化图片和焦点框 */
      private void initImage() {
          Drawable d = getDrawable();
          if (!isInited || d == null) return;
  
          mode = NONE;
          matrix = getImageMatrix();
          mImageWidth = mRotatedImageWidth = d.getIntrinsicWidth();
          mImageHeight = mRotatedImageHeight = d.getIntrinsicHeight();
          //计算出焦点框的中点的坐标和上、下、左、右边的x或y的值
          int viewWidth = getWidth();
          int viewHeight = getHeight();
          float midPointX = viewWidth / 2;
          float midPointY = viewHeight / 2;
          mFocusMidPoint = new PointF(midPointX, midPointY);
  
          if (mStyle == Style.CIRCLE) {
              int focusSize = Math.min(mFocusWidth, mFocusHeight);
              mFocusWidth = focusSize;
              mFocusHeight = focusSize;
          }
          mFocusRect.left = mFocusMidPoint.x - mFocusWidth / 2;
          mFocusRect.right = mFocusMidPoint.x + mFocusWidth / 2;
          mFocusRect.top = mFocusMidPoint.y - mFocusHeight / 2;
          mFocusRect.bottom = mFocusMidPoint.y + mFocusHeight / 2;
  
          //适配焦点框的缩放比例（图片的最小边不小于焦点框的最小边）
          float fitFocusScale = getScale(mImageWidth, mImageHeight, mFocusWidth, mFocusHeight, true);
          mMaxScale = fitFocusScale * MAX_SCALE;
          //适配显示图片的ImageView的缩放比例（图片至少有一边是铺满屏幕的显示的情形）
          float fitViewScale = getScale(mImageWidth, mImageHeight, viewWidth, viewHeight, false);
          //确定最终的缩放比例,在适配焦点框的前提下适配显示图片的ImageView，
          //方案：首先满足适配焦点框，如果还能适配显示图片的ImageView，则适配它，即取缩放比例的最大值。
          //采取这种方案的原因：有可能图片很长或者很高，适配了ImageView的时候可能会宽/高已经小于焦点框的宽/高
          float scale = fitViewScale > fitFocusScale ? fitViewScale : fitFocusScale;
          //图像中点为中心进行缩放
          matrix.setScale(scale, scale, mImageWidth / 2, mImageHeight / 2);
          float[] mImageMatrixValues = new float[9];
          matrix.getValues(mImageMatrixValues); //获取缩放后的mImageMatrix的值
          float transX = mFocusMidPoint.x - (mImageMatrixValues[2] + mImageWidth * mImageMatrixValues[0] / 2);  //X轴方向的位移
          float transY = mFocusMidPoint.y - (mImageMatrixValues[5] + mImageHeight * mImageMatrixValues[4] / 2); //Y轴方向的位移
          matrix.postTranslate(transX, transY);
          setImageMatrix(matrix);
          invalidate();
      }
  
      /** 计算边界缩放比例 isMinScale 是否最小比例，true 最小缩放比例， false 最大缩放比例 */
      private float getScale(int bitmapWidth, int bitmapHeight, int minWidth, int minHeight, boolean isMinScale) {
          float scale;
          float scaleX = (float) minWidth / bitmapWidth;
          float scaleY = (float) minHeight / bitmapHeight;
          if (isMinScale) {
              scale = scaleX > scaleY ? scaleX : scaleY;
          } else {
              scale = scaleX < scaleY ? scaleX : scaleY;
          }
          return scale;
      }
  
      /** 绘制焦点框 */
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
          if (Style.RECTANGLE == mStyle) {
              mFocusPath.addRect(mFocusRect, Path.Direction.CCW);
              canvas.save();
              canvas.clipRect(0, 0, getWidth(), getHeight());
              canvas.clipPath(mFocusPath, Region.Op.DIFFERENCE);
              canvas.drawColor(mMaskColor);
              canvas.restore();
          } else if (Style.CIRCLE == mStyle) {
              float radius = Math.min((mFocusRect.right - mFocusRect.left) / 2, (mFocusRect.bottom - mFocusRect.top) / 2);
              mFocusPath.addCircle(mFocusMidPoint.x, mFocusMidPoint.y, radius, Path.Direction.CCW);
              canvas.save();
              canvas.clipRect(0, 0, getWidth(), getHeight());
              canvas.clipPath(mFocusPath, Region.Op.DIFFERENCE);
              canvas.drawColor(mMaskColor);
              canvas.restore();
          }
          mBorderPaint.setColor(mBorderColor);
          mBorderPaint.setStyle(Paint.Style.STROKE);
          mBorderPaint.setStrokeWidth(mBorderWidth);
          mBorderPaint.setAntiAlias(true);
          canvas.drawPath(mFocusPath, mBorderPaint);
          mFocusPath.reset();
      }
  
      @Override
      public boolean onTouchEvent(MotionEvent event) {
          if (mSaving || null == getDrawable()) {
              return super.onTouchEvent(event);
          }
          switch (event.getAction() & MotionEvent.ACTION_MASK) {
              case MotionEvent.ACTION_DOWN:  //第一个点按下
                  savedMatrix.set(matrix);   //以后每次需要变换的时候，以现在的状态为基础进行变换
                  pA.set(event.getX(), event.getY());
                  pB.set(event.getX(), event.getY());
                  mode = DRAG;
                  break;
              case MotionEvent.ACTION_POINTER_DOWN:  //第二个点按下
                  if (event.getActionIndex() > 1) break;
                  pA.set(event.getX(0), event.getY(0));
                  pB.set(event.getX(1), event.getY(1));
                  midPoint.set((pA.x + pB.x) / 2, (pA.y + pB.y) / 2);
                  oldDist = spacing(pA, pB);
                  savedMatrix.set(matrix);  //以后每次需要变换的时候，以现在的状态为基础进行变换
                  if (oldDist > 10f) mode = ZOOM_OR_ROTATE;//两点之间的距离大于10才有效
                  break;
              case MotionEvent.ACTION_MOVE:
                  if (mode == ZOOM_OR_ROTATE) {
                      PointF pC = new PointF(event.getX(1) - event.getX(0) + pA.x, event.getY(1) - event.getY(0) + pA.y);
                      double a = spacing(pB.x, pB.y, pC.x, pC.y);
                      double b = spacing(pA.x, pA.y, pC.x, pC.y);
                      double c = spacing(pA.x, pA.y, pB.x, pB.y);
                      if (a >= 10) {
                          double cosB = (a * a + c * c - b * b) / (2 * a * c);
                          double angleB = Math.acos(cosB);
                          double PID4 = Math.PI / 4;
                          //旋转时，默认角度在 45 - 135 度之间
                          if (angleB > PID4 && angleB < 3 * PID4) mode = ROTATE;
                          else mode = ZOOM;
                      }
                  }
                  if (mode == DRAG) {
                      matrix.set(savedMatrix);
                      matrix.postTranslate(event.getX() - pA.x, event.getY() - pA.y);
                      fixTranslation();
                      setImageMatrix(matrix);
                  } else if (mode == ZOOM) {
                      float newDist = spacing(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
                      if (newDist > 10f) {
                          matrix.set(savedMatrix);
                          // 这里之所以用 maxPostScale 矫正一下，主要是防止缩放到最大时，继续缩放图片会产生位移
                          float tScale = Math.min(newDist / oldDist, maxPostScale());
                          if (tScale != 0) {
                              matrix.postScale(tScale, tScale, midPoint.x, midPoint.y);
                              fixScale();
                              fixTranslation();
                              setImageMatrix(matrix);
                          }
                      }
                  } else if (mode == ROTATE) {
                      PointF pC = new PointF(event.getX(1) - event.getX(0) + pA.x, event.getY(1) - event.getY(0) + pA.y);
                      double a = spacing(pB.x, pB.y, pC.x, pC.y);
                      double b = spacing(pA.x, pA.y, pC.x, pC.y);
                      double c = spacing(pA.x, pA.y, pB.x, pB.y);
                      if (b > 10) {
                          double cosA = (b * b + c * c - a * a) / (2 * b * c);
                          double angleA = Math.acos(cosA);
                          double ta = pB.y - pA.y;
                          double tb = pA.x - pB.x;
                          double tc = pB.x * pA.y - pA.x * pB.y;
                          double td = ta * pC.x + tb * pC.y + tc;
                          if (td > 0) {
                              angleA = 2 * Math.PI - angleA;
                          }
                          rotation = angleA;
                          matrix.set(savedMatrix);
                          matrix.postRotate((float) (rotation * 180 / Math.PI), midPoint.x, midPoint.y);
                          setImageMatrix(matrix);
                      }
                  }
                  break;
              case MotionEvent.ACTION_UP:
              case MotionEvent.ACTION_POINTER_UP:
                  if (mode == DRAG) {
                      if (spacing(pA, pB) < 50) {
                          long now = System.currentTimeMillis();
                          if (now - doubleClickTime < 500 && spacing(pA, doubleClickPos) < 50) {
                              doubleClick(pA.x, pA.y);
                              now = 0;
                          }
                          doubleClickPos.set(pA);
                          doubleClickTime = now;
                      }
                  } else if (mode == ROTATE) {
                      int rotateLevel = (int) Math.floor((rotation + Math.PI / 4) / (Math.PI / 2));
                      if (rotateLevel == 4) rotateLevel = 0;
                      matrix.set(savedMatrix);
                      matrix.postRotate(90 * rotateLevel, midPoint.x, midPoint.y);
                      if (rotateLevel == 1 || rotateLevel == 3) {
                          int tmp = mRotatedImageWidth;
                          mRotatedImageWidth = mRotatedImageHeight;
                          mRotatedImageHeight = tmp;
                      }
                      fixScale();
                      fixTranslation();
                      setImageMatrix(matrix);
                      sumRotateLevel += rotateLevel;
                  }
                  mode = NONE;
                  break;
          }
          //解决部分机型无法拖动的问题
          ViewCompat.postInvalidateOnAnimation(this);
          return true;
      }
  
      /** 修正图片的缩放比 */
      private void fixScale() {
          float imageMatrixValues[] = new float[9];
          matrix.getValues(imageMatrixValues);
          float currentScale = Math.abs(imageMatrixValues[0]) + Math.abs(imageMatrixValues[1]);
          float minScale = getScale(mRotatedImageWidth, mRotatedImageHeight, mFocusWidth, mFocusHeight, true);
          mMaxScale = minScale * MAX_SCALE;
  
          //保证图片最小是占满中间的焦点空间
          if (currentScale < minScale) {
              float scale = minScale / currentScale;
              matrix.postScale(scale, scale);
          } else if (currentScale > mMaxScale) {
              float scale = mMaxScale / currentScale;
              matrix.postScale(scale, scale);
          }
      }
  
      /** 修正图片的位移 */
      private void fixTranslation() {
          RectF imageRect = new RectF(0, 0, mImageWidth, mImageHeight);
          matrix.mapRect(imageRect);  //获取当前图片（缩放以后的）相对于当前控件的位置区域，超过控件的上边缘或左边缘为负
          float deltaX = 0, deltaY = 0;
          if (imageRect.left > mFocusRect.left) {
              deltaX = -imageRect.left + mFocusRect.left;
          } else if (imageRect.right < mFocusRect.right) {
              deltaX = -imageRect.right + mFocusRect.right;
          }
          if (imageRect.top > mFocusRect.top) {
              deltaY = -imageRect.top + mFocusRect.top;
          } else if (imageRect.bottom < mFocusRect.bottom) {
              deltaY = -imageRect.bottom + mFocusRect.bottom;
          }
          matrix.postTranslate(deltaX, deltaY);
      }
  
      /** 获取当前图片允许的最大缩放比 */
      private float maxPostScale() {
          float imageMatrixValues[] = new float[9];
          matrix.getValues(imageMatrixValues);
          float curScale = Math.abs(imageMatrixValues[0]) + Math.abs(imageMatrixValues[1]);
          return mMaxScale / curScale;
      }
  
      /** 计算两点之间的距离 */
      private float spacing(float x1, float y1, float x2, float y2) {
          float x = x1 - x2;
          float y = y1 - y2;
          return (float) Math.sqrt(x * x + y * y);
      }
  
      /** 计算两点之间的距离 */
      private float spacing(PointF pA, PointF pB) {
          return spacing(pA.x, pA.y, pB.x, pB.y);
      }
  
      /** 双击触发的方法 */
      private void doubleClick(float x, float y) {
          float p[] = new float[9];
          matrix.getValues(p);
          float curScale = Math.abs(p[0]) + Math.abs(p[1]);
          float minScale = getScale(mRotatedImageWidth, mRotatedImageHeight, mFocusWidth, mFocusHeight, true);
          if (curScale < mMaxScale) {
              //每次双击的时候，缩放加 minScale
              float toScale = Math.min(curScale + minScale, mMaxScale) / curScale;
              matrix.postScale(toScale, toScale, x, y);
          } else {
              float toScale = minScale / curScale;
              matrix.postScale(toScale, toScale, x, y);
              fixTranslation();
          }
          setImageMatrix(matrix);
      }
  
      /**
       * @param expectWidth     期望的宽度
       * @param exceptHeight    期望的高度
       * @param isSaveRectangle 是否按矩形区域保存图片
       * @return 裁剪后的Bitmap
       */
      public Bitmap getCropBitmap(int expectWidth, int exceptHeight, boolean isSaveRectangle) {
          if (expectWidth <= 0 || exceptHeight < 0) return null;
          Bitmap srcBitmap = ((BitmapDrawable) getDrawable()).getBitmap();
          srcBitmap = rotate(srcBitmap, sumRotateLevel * 90);  //最好用level，因为角度可能不是90的整数
          return makeCropBitmap(srcBitmap, mFocusRect, getImageMatrixRect(), expectWidth, exceptHeight, isSaveRectangle);
      }
  
      /**
       * @param bitmap  要旋转的图片
       * @param degrees 选择的角度（单位 度）
       * @return 旋转后的Bitmap
       */
      private Bitmap rotate(Bitmap bitmap, int degrees) {
          if (degrees != 0 && bitmap != null) {
              Matrix matrix = new Matrix();
              matrix.setRotate(degrees, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2);
              try {
                  Bitmap rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                  if (bitmap != rotateBitmap) {
  //                    bitmap.recycle();
                      return rotateBitmap;
                  }
              } catch (OutOfMemoryError ex) {
                  ex.printStackTrace();
              }
          }
          return bitmap;
      }
  
      /**
       * @return 获取当前图片显示的矩形区域
       */
      private RectF getImageMatrixRect() {
          RectF rectF = new RectF();
          rectF.set(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight());
          matrix.mapRect(rectF);
          return rectF;
      }
  
      /**
       * @param bitmap          需要裁剪的图片
       * @param focusRect       中间需要裁剪的矩形区域
       * @param imageMatrixRect 当前图片在屏幕上的显示矩形区域
       * @param expectWidth     希望获得的图片宽度，如果图片宽度不足时，拉伸图片
       * @param exceptHeight    希望获得的图片高度，如果图片高度不足时，拉伸图片
       * @param isSaveRectangle 是否希望按矩形区域保存图片
       * @return 裁剪后的图片的Bitmap
       */
      private Bitmap makeCropBitmap(Bitmap bitmap, RectF focusRect, RectF imageMatrixRect, int expectWidth, int exceptHeight, boolean isSaveRectangle) {
          float scale = imageMatrixRect.width() / bitmap.getWidth();
          int left = (int) ((focusRect.left - imageMatrixRect.left) / scale);
          int top = (int) ((focusRect.top - imageMatrixRect.top) / scale);
          int width = (int) (focusRect.width() / scale);
          int height = (int) (focusRect.height() / scale);
  
          if (left < 0) left = 0;
          if (top < 0) top = 0;
          if (left + width > bitmap.getWidth()) width = bitmap.getWidth() - left;
          if (top + height > bitmap.getHeight()) height = bitmap.getHeight() - top;
  
          try {
              bitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
              if (expectWidth != width || exceptHeight != height) {
                  bitmap = Bitmap.createScaledBitmap(bitmap, expectWidth, exceptHeight, true);
                  if (mStyle == CropImageView.Style.CIRCLE && !isSaveRectangle) {
                      //如果是圆形，就将图片裁剪成圆的
                      int length = Math.min(expectWidth, exceptHeight);
                      int radius = length / 2;
                      Bitmap circleBitmap = Bitmap.createBitmap(length, length, Bitmap.Config.ARGB_8888);
                      Canvas canvas = new Canvas(circleBitmap);
                      BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                      Paint paint = new Paint();
                      paint.setShader(bitmapShader);
                      canvas.drawCircle(expectWidth / 2f, exceptHeight / 2f, radius, paint);
                      bitmap = circleBitmap;
                  }
              }
          } catch (OutOfMemoryError e) {
              e.printStackTrace();
          }
          return bitmap;
      }
  
      /**
       * @param folder          希望保存的文件夹
       * @param expectWidth     希望保存的图片宽度
       * @param exceptHeight    希望保存的图片高度
       * @param isSaveRectangle 是否希望按矩形区域保存图片
       */
      public void saveBitmapToFile(File folder, int expectWidth, int exceptHeight, boolean isSaveRectangle) {
          if (mSaving) return;
          mSaving = true;
          final Bitmap croppedImage = getCropBitmap(expectWidth, exceptHeight, isSaveRectangle);
          Bitmap.CompressFormat outputFormat = Bitmap.CompressFormat.JPEG;
          File saveFile = createFile(folder, "IMG_", ".jpg");
          if (mStyle == CropImageView.Style.CIRCLE && !isSaveRectangle) {
              outputFormat = Bitmap.CompressFormat.PNG;
              saveFile = createFile(folder, "IMG_", ".png");
          }
          final Bitmap.CompressFormat finalOutputFormat = outputFormat;
          final File finalSaveFile = saveFile;
          new Thread() {
              @Override
              public void run() {
                  saveOutput(croppedImage, finalOutputFormat, finalSaveFile);
              }
          }.start();
      }
  
      /** 根据系统时间、前缀、后缀产生一个文件 */
      private File createFile(File folder, String prefix, String suffix) {
          if (!folder.exists() || !folder.isDirectory()) folder.mkdirs();
          try {
              File nomedia = new File(folder, ".nomedia");  //在当前文件夹底下创建一个 .nomedia 文件
              if (!nomedia.exists()) nomedia.createNewFile();
          } catch (IOException e) {
              e.printStackTrace();
          }
          SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA);
          String filename = prefix + dateFormat.format(new Date(System.currentTimeMillis())) + suffix;
          return new File(folder, filename);
      }
  
      /** 将图片保存在本地 */
      private void saveOutput(Bitmap croppedImage, Bitmap.CompressFormat outputFormat, File saveFile) {
          OutputStream outputStream = null;
          try {
              outputStream = getContext().getContentResolver().openOutputStream(Uri.fromFile(saveFile));
              if (outputStream != null) croppedImage.compress(outputFormat, 90, outputStream);
              Message.obtain(mHandler, SAVE_SUCCESS, saveFile).sendToTarget();
          } catch (IOException ex) {
              ex.printStackTrace();
              Message.obtain(mHandler, SAVE_ERROR, saveFile).sendToTarget();
          } finally {
              if (outputStream != null) {
                  try {
                      outputStream.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
          mSaving = false;
          croppedImage.recycle();
      }
  
      private static class InnerHandler extends Handler {
          public InnerHandler() {
              super(Looper.getMainLooper());
          }
  
          @Override
          public void handleMessage(Message msg) {
              File saveFile = (File) msg.obj;
              switch (msg.what) {
                  case SAVE_SUCCESS:
                      if (mListener != null) mListener.onBitmapSaveSuccess(saveFile);
                      break;
                  case SAVE_ERROR:
                      if (mListener != null) mListener.onBitmapSaveError(saveFile);
                      break;
              }
          }
      }
  
      /** 图片保存完成的监听 */
      private static OnBitmapSaveCompleteListener mListener;
  
      public interface OnBitmapSaveCompleteListener {
          void onBitmapSaveSuccess(File file);
  
          void onBitmapSaveError(File file);
      }
  
      public void setOnBitmapSaveCompleteListener(OnBitmapSaveCompleteListener listener) {
          mListener = listener;
      }
  
      /** 返回焦点框宽度 */
      public int getFocusWidth() {
          return mFocusWidth;
      }
  
      /** 设置焦点框的宽度 */
      public void setFocusWidth(int width) {
          mFocusWidth = width;
          initImage();
      }
  
      /** 获取焦点框的高度 */
      public int getFocusHeight() {
          return mFocusHeight;
      }
  
      /** 设置焦点框的高度 */
      public void setFocusHeight(int height) {
          mFocusHeight = height;
          initImage();
      }
  
      /** 返回阴影颜色 */
      public int getMaskColor() {
          return mMaskColor;
      }
  
      /** 设置阴影颜色 */
      public void setMaskColor(int color) {
          mMaskColor = color;
          invalidate();
      }
  
      /** 返回焦点框边框颜色 */
      public int getFocusColor() {
          return mBorderColor;
      }
  
      /** 设置焦点框边框颜色 */
      public void setBorderColor(int color) {
          mBorderColor = color;
          invalidate();
      }
  
      /** 返回焦点框边框绘制宽度 */
      public float getBorderWidth() {
          return mBorderWidth;
      }
  
      /** 设置焦点边框宽度 */
      public void setBorderWidth(int width) {
          mBorderWidth = width;
          invalidate();
      }
  
      /** 设置焦点框的形状 */
      public void setFocusStyle(Style style) {
          this.mStyle = style;
          invalidate();
      }
  
      /** 获取焦点框的形状 */
      public Style getFocusStyle() {
          return mStyle;
      }
  }