Android Open Source - UniversalImagePick Crop Image View






From Project

Back to project page UniversalImagePick.

License

The source code is released under:

Apache License

If you think the Android project UniversalImagePick listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.luffyjet.universalimagepick.widget;
/*w w w  .  j a  v  a2s.c  om*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import android.R.integer;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

/**
 * 
 * @author Luffyjet
 * @version 1.0.0
 * @since 2014-9-19 {@link https://github.com/luffyjet}
 */
public class CropImageView extends ImageView {

  private static final String TAG = "CropImageView";
  /**
   * ??????????
   */
  private static final long REFRESH_DELAY = 10L;
  /**
   * ????
   */
  private static final int BORDER_WIDTH = 1;
  /**
   * ???????????
   */
  private static final long DOUBLE_CLICK_TIME_SPACE = 300;// ms
  /**
   * ???????????????
   */
  private static final float DISTANCE = 10f;
  /**
   * ??????????
   */
  private long lastClickTime;// ms
  /**
   * ??????
   */
  private static int CROP_WIDTH = 460;
  private static int CROP_HEIGHT = 460;
  /**
   * ???????(CompressFormat default JPEG)
   */
  private static CompressFormat DEFAULT_FORMAT = CompressFormat.JPEG;
  /**
   * ???????(Compress quality default 80)
   */
  private static int DEFAULT_QUALITY = 80;
  /**
   * ??
   */
  private Paint mPaint;
  /**
   * ????
   */
  private int maskColor = 0x7A000000;// ??????
  /**
   * ?????
   */
  private Rect mFrame;
  /**
   * ????? (the screen width and height)
   */
  private int mScreenWidth;
  private int mScreenHeight;

  private int statusBarHeight;

  private Activity mActivity;

  private Mode mMode;

  private Matrix mSupMatrix = new Matrix();
  private Matrix mLastMatrix = new Matrix();

  private PointF mStartPF = new PointF();
  private PointF mCenterPF = new PointF();

  private float mLastDist = 1.0f;

  private final static float DOUBLE_CLICK_SCALE = 1.4f;

  private float mScale;

  private float mLastScale;
  
  private float offset = 100f;

  public CropImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
  }

  public CropImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  }

  public CropImageView(Context context) {
    super(context);
    init(context);
  }

  /**
   * ?????(touch status)
   */
  static enum Mode {
    NONE, DRAG, ZOOM;
  }

  /**
   * ???????????? (init Mask CropRect...)
   * 
   * @param context
   */
  private final void init(Context context) {
    if (context instanceof Activity) {
      mActivity = (Activity) context;
      mPaint = new Paint();

      DisplayMetrics dm = new DisplayMetrics();
      mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
      mScreenWidth = dm.widthPixels;
      mScreenHeight = dm.heightPixels;

      mFrame = getRect(mScreenWidth, mScreenHeight);
    } else {
      Log.e(TAG, "context must be a instance of Activity");
    }
  }

  /**
   * @param resId
   */
  public void setImageResource(int resId) {
    setImageResource(resId, null);
  }

  /**
   * 
   * @param resId
   * @param options
   */
  public void setImageResource(int resId, Options options) {
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId, options);
    setBitmap(bitmap, mScreenWidth, mScreenHeight);
  }

  /**
   * 
   * @param bitmap
   */
  public void setImageBitmap(Bitmap bitmap) {
    setBitmap(bitmap, mScreenWidth, mScreenHeight);
  }

  /**
   * 
   * @param bitmap
   * @param screenWidht
   * @param screenHeight
   */
  public void setBitmap(Bitmap bitmap, int screenWidht, int screenHeight) {
    int bmpWidth = bitmap.getWidth();
    int bmpHeight = bitmap.getHeight();
    // ?????(compute scale)
    float scaleX = (float) CROP_WIDTH / bmpWidth;
    float scaleY = (float) CROP_HEIGHT / bmpHeight;
    // ????????,??????CROP_HEIGHT??????????CROP_WIDTH(if image's width >
    // height ,so scale to fit CROP_HEIGHT)
    float scale = scaleX < scaleY ? scaleY : scaleX;

    Matrix matrix = new Matrix();
    // ????????X?(The X coordinate of the left side of the bitmap)
    float pivotX = (screenWidht - bmpWidth * scale) / 2;
    // ????????Y?(The Y coordinate of the top of the bitmap)
    float pivotY = (screenHeight - bmpHeight * scale) / 2;
    // set bitmap to this Imageview
    setImageDrawable(new BitmapDrawable(getResources(), bitmap));
    // scale and translate ImageView
    setScaleType(ScaleType.MATRIX);
    matrix.postScale(scale, scale);
    matrix.postTranslate(pivotX, pivotY);
    setImageMatrix(matrix);
  }

  /**
   * ???????????(get crop rect)
   * 
   * @param screenW
   *            ????
   * @param screenH
   *            ????
   * @return
   */
  private Rect getRect(int screenW, int screenH) {
    // ??????????(we need to minus BORDER_WIDTH)
    int rectLeft = (screenW - CROP_WIDTH - BORDER_WIDTH) / 2;
    int rectRight = screenW - rectLeft;
    int rectTop = (screenH - CROP_HEIGHT - BORDER_WIDTH) / 2;
    int rectBottom = screenH - rectTop;
    Rect rect = new Rect(rectLeft, rectTop, rectRight, rectBottom);
    return rect;
  }

  @Override
  public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // ??????????? (get screen w/h)
    int width = canvas.getWidth();
    int height = canvas.getHeight();

    mPaint.setColor(maskColor);
    // ?????????????? (draw mask)
    canvas.drawRect(0, 0, width, mFrame.top, mPaint);// ???
    canvas.drawRect(0, mFrame.top, mFrame.left, mFrame.bottom, mPaint);// ????
    canvas.drawRect(mFrame.right, mFrame.top, width, mFrame.bottom, mPaint);// ??????
    canvas.drawRect(0, mFrame.bottom, width, height, mPaint);// ???

    // ??????????(draw line)
    mPaint.setColor(Color.WHITE);
    canvas.drawRect(mFrame.left, mFrame.top, mFrame.right, mFrame.top + BORDER_WIDTH, mPaint);// ????????
    canvas.drawRect(mFrame.left, mFrame.top, mFrame.left + BORDER_WIDTH, mFrame.bottom, mPaint);// ??????
    canvas.drawRect(mFrame.right - BORDER_WIDTH, mFrame.top, mFrame.right, mFrame.bottom, mPaint);// ????????
    canvas.drawRect(mFrame.left, mFrame.bottom - BORDER_WIDTH, mFrame.right, mFrame.bottom, mPaint);// ??

    // ???????????????????? (refresh the border)
    postInvalidateDelayed(REFRESH_DELAY, mFrame.left, mFrame.top, mFrame.right, mFrame.bottom);
  }

  /**
   * ????????(crop)
   * 
   * @return Bitmap
   */
  public Bitmap cropBitmap() {
    Bitmap resultBitmap = null;
    try {
      // ??????????Content View
      View view = mActivity.getWindow().getDecorView();
      view.setDrawingCacheEnabled(true);
      view.buildDrawingCache();
      // ??????????Bitmap
      Bitmap screenBitmap = view.getDrawingCache();
      // get statusBarHeight
      Rect frame = new Rect();
      mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
      statusBarHeight = frame.top;
      // ????Crop???Bitmap
      resultBitmap = Bitmap.createBitmap(screenBitmap, mFrame.left + BORDER_WIDTH, mFrame.top + statusBarHeight + BORDER_WIDTH, mFrame.right - mFrame.left - 2 * BORDER_WIDTH, mFrame.bottom - mFrame.top - 2 * BORDER_WIDTH);
      // ??????
      view.destroyDrawingCache();
      screenBitmap.recycle();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return resultBitmap;
  }

  /**
   * 
   * @param filePath
   * @return
   */
  public Uri saveCropBitmap(File filePath){
    return saveCropBitmap(filePath, DEFAULT_FORMAT, DEFAULT_QUALITY);
  }
  
  /**
   * ???????????(crop and save img)
   * @param filePath  file save path in SDCard
   * @param format  just like JPEG,PNG
   * @param quality 1-100
   * @return URI of the Image or Null
   */
  public Uri saveCropBitmap(File filePath,CompressFormat format, int quality) {
    if (filePath == null) {
      return null;
    }
    if (!filePath.getParentFile().exists()) {
      filePath.getParentFile().mkdirs();
    }
    Uri uri = null;
    FileOutputStream fos = null;
    try {
      fos = new FileOutputStream(filePath);
      if (null != fos) {
        cropBitmap().compress(format, quality, fos);
        fos.flush();
        fos.close();
        uri = Uri.fromFile(filePath);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }finally{
      try {
        fos.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return uri;
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction() & MotionEvent.ACTION_MASK) {

      case MotionEvent.ACTION_DOWN:

        mSupMatrix.set(getImageMatrix());
        mLastMatrix.set(mSupMatrix);
        mStartPF.set(event.getX(), event.getY());

        if (1 == event.getPointerCount()) {
          // ?????????????????????????
          if (event.getEventTime() - lastClickTime < DOUBLE_CLICK_TIME_SPACE) {
            onDoubleClick(event);
          } else {
            mMode = Mode.DRAG;
          }
        }

        lastClickTime = event.getEventTime();
        break;
      case MotionEvent.ACTION_POINTER_DOWN:
        mLastDist = computeDistance(event);
        if (mLastDist > DISTANCE) {
          mLastMatrix.set(mSupMatrix);
          computeCenterPoint(mCenterPF, event);
          mMode = Mode.ZOOM;
        }
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_POINTER_UP:
        mMode = Mode.NONE;
        break;
      case MotionEvent.ACTION_MOVE:
        if (mMode == Mode.DRAG) {
          // TODO ??????(drag range,there have a bug)
          if (event.getX() >= offset && event.getX() < mScreenWidth - offset && event.getY() >= offset && event.getY() < mScreenHeight - offset) {
            mSupMatrix.set(mLastMatrix);
            mSupMatrix.postTranslate(event.getX() - mStartPF.x, event.getY() - mStartPF.y);
          }
        } else if (mMode == Mode.ZOOM) {
          float newDist = computeDistance(event);
          if (newDist > DISTANCE) {
            mSupMatrix.set(mLastMatrix);
            mScale = newDist / mLastDist;
            mSupMatrix.postScale(mScale, mScale, mCenterPF.x, mCenterPF.y);
          }
        }
        setImageMatrix(mSupMatrix);
        break;
    }
    return true;
  }

  /**
   * ?????? double click
   * 
   * @param event
   */
  private void onDoubleClick(MotionEvent event) {
    if (mLastScale > 1.0f) {
      mLastScale = 1.0f / mLastScale;
    } else {
      mLastScale = DOUBLE_CLICK_SCALE;
    }
    mSupMatrix.postScale(mLastScale, mLastScale);
    setImageMatrix(mSupMatrix);
  }

  /**
   * ???????
   * 
   * @param event
   * @return
   */
  @SuppressLint("FloatMath")
  private float computeDistance(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return FloatMath.sqrt(x * x + y * y);
  }

  /**
   * ???????
   * 
   * @param point
   * @param event
   */
  private void computeCenterPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
  }

}




Java Source Code List

com.luffyjet.universalimagepick.App.java
com.luffyjet.universalimagepick.Constants.java
com.luffyjet.universalimagepick.MainActivity.java
com.luffyjet.universalimagepick.Test.java
com.luffyjet.universalimagepick.adapter.BucketAdapter.java
com.luffyjet.universalimagepick.adapter.GalleryAdapter.java
com.luffyjet.universalimagepick.adapter.PickGridAdapter.java
com.luffyjet.universalimagepick.adapter.PreviewAdapter.java
com.luffyjet.universalimagepick.adapter.ResultAdapter.java
com.luffyjet.universalimagepick.model.ImageBucket.java
com.luffyjet.universalimagepick.model.Image.java
com.luffyjet.universalimagepick.model.ImagesHelper.java
com.luffyjet.universalimagepick.model.Thumbnail.java
com.luffyjet.universalimagepick.ui.BaseActivity.java
com.luffyjet.universalimagepick.ui.GalleryActivity.java
com.luffyjet.universalimagepick.ui.PickActivity.java
com.luffyjet.universalimagepick.utils.LogUtil.java
com.luffyjet.universalimagepick.widget.CropImageView.java
com.luffyjet.universalimagepick.widget.CustomGridView.java
com.luffyjet.universalimagepick.widget.MulitPointTouchListener.java
com.luffyjet.universalimagepick.widget.ViewfinderView.java