Android圖片自由選區裁剪庫Demo
阿新 • • 發佈:2018-12-09
Demo地址:https://gitee.com/olleh/ImageCrop.git
package cn.com.gyq.crop; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.media.ExifInterface; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; import java.io.IOException; import cn.com.gyq.crop.view.CropImageView; public class MainActivity extends Activity { CropImageView cropImageView; Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); cropImageView = (CropImageView) findViewById(R.id.cropImageView); button = (Button) findViewById(R.id.cropOk); Glide.with(this) .load(R.drawable.test) .asBitmap() .into(cropImageView); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { button.setText("Rect:" + cropImageView.getImageRect()); Toast.makeText(MainActivity.this, "Rect:" + cropImageView.getImageRect(), Toast.LENGTH_SHORT).show(); } }); } }
package cn.com.gyq.crop.view; import android.content.Context; import android.graphics.Bitmap; 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.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ImageView; import cn.com.gyq.crop.edge.Edge; import cn.com.gyq.crop.handle.CropWindowEdgeSelector; import cn.com.gyq.crop.util.CatchEdgeUtil; import cn.com.gyq.crop.util.UIUtil; public class CropImageView extends ImageView { //裁剪框邊框畫筆 private Paint mBorderPaint; //裁剪框九宮格畫筆 private Paint mGuidelinePaint; //繪製裁剪邊框四個角的畫筆 private Paint mCornerPaint; //判斷手指位置是否處於縮放裁剪框位置的範圍:如果是當手指移動的時候裁剪框會相應的變化大小 //否則手指移動的時候就是拖動裁剪框使之隨著手指移動 private float mScaleRadius; private float mCornerThickness; private float mBorderThickness; //四個角小短邊的長度 private float mCornerLength; //用來表示圖片邊界的矩形 private RectF mBitmapRect = new RectF(); //手指位置距離裁剪框的偏移量 private PointF mTouchOffset = new PointF(); private CropWindowEdgeSelector mPressedCropWindowEdgeSelector; public CropImageView(Context context) { super(context); init(context); } public CropImageView(Context context, AttributeSet attributeSet) { super(context, attributeSet); init(context); } /** * 裡面的值暫時寫死,也可以從AttributeSet裡面來配置 * * @param context */ private void init(@NonNull Context context) { mBorderPaint = new Paint(); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setStrokeWidth(UIUtil.dip2px(context, 3)); mBorderPaint.setColor(Color.parseColor("#f50d86")); mGuidelinePaint = new Paint(); mGuidelinePaint.setStyle(Paint.Style.STROKE); mGuidelinePaint.setStrokeWidth(UIUtil.dip2px(context, 1)); mGuidelinePaint.setColor(Color.parseColor("#f50d86")); mCornerPaint = new Paint(); mCornerPaint.setStyle(Paint.Style.STROKE); mCornerPaint.setStrokeWidth(UIUtil.dip2px(context, 5)); mCornerPaint.setColor(Color.parseColor("#f50d86")); mScaleRadius = UIUtil.dip2px(context, 24); mBorderThickness = UIUtil.dip2px(context, 3); mCornerThickness = UIUtil.dip2px(context, 5); mCornerLength = UIUtil.dip2px(context, 20); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); mBitmapRect = getBitmapRect(); initCropWindow(mBitmapRect); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //繪製九宮格引導線 drawGuidelines(canvas); //繪製裁剪邊框 drawBorder(canvas); //繪製裁剪邊框的四個角 drawCorners(canvas); } @Override public boolean onTouchEvent(MotionEvent event) { if (!isEnabled()) { return false; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: onActionDown(event.getX(), event.getY()); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: getParent().requestDisallowInterceptTouchEvent(false); onActionUp(); return true; case MotionEvent.ACTION_MOVE: onActionMove(event.getX(), event.getY()); getParent().requestDisallowInterceptTouchEvent(true); return true; default: return false; } } /** * 獲取選中的範圍 */ public Rect getImageRect() { final Drawable drawable = getDrawable(); if (drawable == null || !(drawable instanceof BitmapDrawable)) { return null; } final float[] matrixValues = new float[9]; getImageMatrix().getValues(matrixValues); final float scaleX = matrixValues[Matrix.MSCALE_X]; final float scaleY = matrixValues[Matrix.MSCALE_Y]; final float transX = matrixValues[Matrix.MTRANS_X]; final float transY = matrixValues[Matrix.MTRANS_Y]; float bitmapLeft = (transX < 0) ? Math.abs(transX) : 0; float bitmapTop = (transY < 0) ? Math.abs(transY) : 0; final Bitmap originalBitmap = ((BitmapDrawable) drawable).getBitmap(); final float cropX = (bitmapLeft + Edge.LEFT.getCoordinate()) / scaleX; final float cropY = (bitmapTop + Edge.TOP.getCoordinate()) / scaleY; final float cropWidth = Math.min(Edge.getWidth() / scaleX, originalBitmap.getWidth() - cropX); final float cropHeight = Math.min(Edge.getHeight() / scaleY, originalBitmap.getHeight() - cropY); return new Rect((int)cropX,(int)cropY,(int)(cropX+cropWidth),(int)(cropY+cropHeight)); } /** * 獲取裁剪好的BitMap */ public Bitmap getCroppedImage() { final Drawable drawable = getDrawable(); if (drawable == null || !(drawable instanceof BitmapDrawable)) { return null; } final float[] matrixValues = new float[9]; getImageMatrix().getValues(matrixValues); final float scaleX = matrixValues[Matrix.MSCALE_X]; final float scaleY = matrixValues[Matrix.MSCALE_Y]; final float transX = matrixValues[Matrix.MTRANS_X]; final float transY = matrixValues[Matrix.MTRANS_Y]; float bitmapLeft = (transX < 0) ? Math.abs(transX) : 0; float bitmapTop = (transY < 0) ? Math.abs(transY) : 0; final Bitmap originalBitmap = ((BitmapDrawable) drawable).getBitmap(); final float cropX = (bitmapLeft + Edge.LEFT.getCoordinate()) / scaleX; final float cropY = (bitmapTop + Edge.TOP.getCoordinate()) / scaleY; final float cropWidth = Math.min(Edge.getWidth() / scaleX, originalBitmap.getWidth() - cropX); final float cropHeight = Math.min(Edge.getHeight() / scaleY, originalBitmap.getHeight() - cropY); return Bitmap.createBitmap(originalBitmap, (int) cropX, (int) cropY, (int) cropWidth, (int) cropHeight); } /** * 獲取圖片ImageView周圍的邊界組成的RectF物件 */ private RectF getBitmapRect() { final Drawable drawable = getDrawable(); if (drawable == null) { return new RectF(); } final float[] matrixValues = new float[9]; getImageMatrix().getValues(matrixValues); final float scaleX = matrixValues[Matrix.MSCALE_X]; final float scaleY = matrixValues[Matrix.MSCALE_Y]; final float transX = matrixValues[Matrix.MTRANS_X]; final float transY = matrixValues[Matrix.MTRANS_Y]; final int drawableIntrinsicWidth = drawable.getIntrinsicWidth(); final int drawableIntrinsicHeight = drawable.getIntrinsicHeight(); final int drawableDisplayWidth = Math.round(drawableIntrinsicWidth * scaleX); final int drawableDisplayHeight = Math.round(drawableIntrinsicHeight * scaleY); final float left = Math.max(transX, 0); final float top = Math.max(transY, 0); final float right = Math.min(left + drawableDisplayWidth, getWidth()); final float bottom = Math.min(top + drawableDisplayHeight, getHeight()); return new RectF(left, top, right, bottom); } /** * 初始化裁剪框 * * @param bitmapRect */ private void initCropWindow(@NonNull RectF bitmapRect) { //裁剪框距離圖片左右的padding值 final float horizontalPadding = 0.01f * bitmapRect.width(); final float verticalPadding = 0.01f * bitmapRect.height(); //初始化裁剪框上下左右四條邊 Edge.LEFT.initCoordinate(bitmapRect.left + horizontalPadding); Edge.TOP.initCoordinate(bitmapRect.top + verticalPadding); Edge.RIGHT.initCoordinate(bitmapRect.right - horizontalPadding); Edge.BOTTOM.initCoordinate(bitmapRect.bottom - verticalPadding); } private void drawGuidelines(@NonNull Canvas canvas) { final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); final float oneThirdCropWidth = Edge.getWidth() / 3; final float x1 = left + oneThirdCropWidth; //引導線豎直方向第一條線 canvas.drawLine(x1, top, x1, bottom, mGuidelinePaint); final float x2 = right - oneThirdCropWidth; //引導線豎直方向第二條線 canvas.drawLine(x2, top, x2, bottom, mGuidelinePaint); final float oneThirdCropHeight = Edge.getHeight() / 3; final float y1 = top + oneThirdCropHeight; //引導線水平方向第一條線 canvas.drawLine(left, y1, right, y1, mGuidelinePaint); final float y2 = bottom - oneThirdCropHeight; //引導線水平方向第二條線 canvas.drawLine(left, y2, right, y2, mGuidelinePaint); } private void drawBorder(@NonNull Canvas canvas) { canvas.drawRect(Edge.LEFT.getCoordinate(), Edge.TOP.getCoordinate(), Edge.RIGHT.getCoordinate(), Edge.BOTTOM.getCoordinate(), mBorderPaint); } private void drawCorners(@NonNull Canvas canvas) { final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); //簡單的數學計算 final float lateralOffset = (mCornerThickness - mBorderThickness) / 2f; final float startOffset = mCornerThickness - (mBorderThickness / 2f); //左上角左面的短線 canvas.drawLine(left - lateralOffset, top - startOffset, left - lateralOffset, top + mCornerLength, mCornerPaint); //左上角上面的短線 canvas.drawLine(left - startOffset, top - lateralOffset, left + mCornerLength, top - lateralOffset, mCornerPaint); //右上角右面的短線 canvas.drawLine(right + lateralOffset, top - startOffset, right + lateralOffset, top + mCornerLength, mCornerPaint); //右上角上面的短線 canvas.drawLine(right + startOffset, top - lateralOffset, right - mCornerLength, top - lateralOffset, mCornerPaint); //左下角左面的短線 canvas.drawLine(left - lateralOffset, bottom + startOffset, left - lateralOffset, bottom - mCornerLength, mCornerPaint); //左下角底部的短線 canvas.drawLine(left - startOffset, bottom + lateralOffset, left + mCornerLength, bottom + lateralOffset, mCornerPaint); //右下角左面的短線 canvas.drawLine(right + lateralOffset, bottom + startOffset, right + lateralOffset, bottom - mCornerLength, mCornerPaint); //右下角底部的短線 canvas.drawLine(right + startOffset, bottom + lateralOffset, right - mCornerLength, bottom + lateralOffset, mCornerPaint); } /** * 處理手指按下事件 * @param x 手指按下時水平方向的座標 * @param y 手指按下時豎直方向的座標 */ private void onActionDown(float x, float y) { //獲取邊框的上下左右四個座標點的座標 final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); //獲取手指所在位置位於圖二種的A,B,C,D位置種哪一種 mPressedCropWindowEdgeSelector = CatchEdgeUtil.getPressedHandle(x, y, left, top, right, bottom, mScaleRadius); if (mPressedCropWindowEdgeSelector != null) { //計算手指按下的位置與裁剪框的偏移量 CatchEdgeUtil.getOffset(mPressedCropWindowEdgeSelector, x, y, left, top, right, bottom, mTouchOffset); invalidate(); } } private void onActionUp() { if (mPressedCropWindowEdgeSelector != null) { mPressedCropWindowEdgeSelector = null; invalidate(); } } private void onActionMove(float x, float y) { if (mPressedCropWindowEdgeSelector == null) { return; } x += mTouchOffset.x; y += mTouchOffset.y; mPressedCropWindowEdgeSelector.updateCropWindow(x, y, mBitmapRect); invalidate(); } }