android 圖片任意裁剪(自定義裁剪,相簿)
阿新 • • 發佈:2019-01-04
執行效果
提醒:許可權在6.0及以上需申請許可權(圖上使用的是6.0以下手機)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
關鍵1:怎麼把需要裁剪的圖片匯入到自定義的裁剪控制元件
相簿中選中的圖片地址獲取
//獲取相簿中圖片的路徑 返回圖片路徑
private String initPA(Intent data){
//通過ContentResolver介面訪問ContentProvider所提供的資料
ContentResolver resolver=getContentResolver();
Uri uri=data.getData();
try {
//顯示得到的bitmap圖片
Bitmap bm= MediaStore.Images.Media.getBitmap(resolver,uri);
}catch (IOException e){
e.printStackTrace();
}
String[] proj={MediaStore.Images.Media.DATA};
Cursor cursor=managedQuery(uri,proj,null,null,null);
int column_index=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path=cursor.getString(column_index);
Log.e("path>>",path);
return path;
}
關鍵二:怎麼儲存
需要自己定義個資料夾把繪製好的圖片儲存到資料夾中
//儲存圖片
public void saveBitmap(Context context,Bitmap bmp) {
File appDir = new File(Environment.getExternalStorageDirectory (), "Boohee");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 其次把檔案插入到系統圖庫
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 最後通知相簿更新
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path)));
}
補充:attrs程式碼
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Life_CropImage">
<attr name="life_Crop_ratio" format="float"/>
</declare-styleable>
</resources>
xml全部程式碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="wz.com.mycut.MainActivity">
<wz.com.mycut.SeniorCropImageView
android:id="@+id/my_crop"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button" />
</RelativeLayout>
MainActivity全部程式碼
package wz.com.mycut;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
//地址
String path="http://p4.qhimg.com/t01b090f22c87857c1c.jpg";
//裁剪框
SeniorCropImageView mseniorCropImageView;
MainActivity mActivity;
ProgressBar pb;
//圖片資源
ImageView img;
//裁剪後的圖片
Bitmap bitmap=null;
//儲存圖片按鈕
Button button=null;
//相簿跳轉需要的引數
private final String IMAGE_TYPE="image/*";
private final int IMAGE_CODE=111;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//選擇圖片
initDialog();
//初始化介面元件
initView();
//設定裁剪框的外邊距(padding)
mseniorCropImageView.setCropRectPadding(0f);
//儲存裁剪後的圖片
bitmap=mseniorCropImageView.saveCrop();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
saveBitmap(MainActivity.this,mseniorCropImageView.saveCrop());
Toast.makeText(MainActivity.this,"圖片儲存成功",Toast.LENGTH_LONG).show();
}
});
}
//初始化介面元件
private void initView(){
button=(Button) this.findViewById(R.id.button);
//例項化裁剪物件
mseniorCropImageView =(SeniorCropImageView) this.findViewById(R.id.my_crop);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(data==null){
Toast.makeText(this,"沒有獲取到返回的圖片",Toast.LENGTH_LONG).show();
}
if (resultCode==Activity.RESULT_OK){
if (requestCode==IMAGE_CODE){
path=initPA(data);
//獲取圖片路徑
//裁剪框顯示圖片
mseniorCropImageView.setImagePath(path);
}
}
}
//對話方塊選擇圖片
private void initDialog(){
//宣告對話方塊
AlertDialog.Builder dialog=new AlertDialog.Builder(this);
//對話方塊顯示的列表文字資源
final String[] name={"相簿","相機"};
//設定標題
dialog.setTitle("圖片選擇");
dialog.setItems(name, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i){
case 0:
//跳轉到相簿
initPic();
// Toast.makeText(MainActivity.this,"你點選了相簿",Toast.LENGTH_LONG).show();
break;
case 1:
//跳轉到相機
Toast.makeText(MainActivity.this,"你點選了相機",Toast.LENGTH_LONG).show();
break;
}
}
});
//顯示
dialog.show();
}
//跳轉到相簿,選擇圖片
private void initPic() {
Intent pintent=new Intent(Intent.ACTION_GET_CONTENT);
pintent.setType(IMAGE_TYPE);
startActivityForResult(pintent,IMAGE_CODE);
}
//獲取相簿中圖片的路徑 返回圖片路徑
private String initPA(Intent data){
//通過ContentResolver介面訪問ContentProvider所提供的資料
ContentResolver resolver=getContentResolver();
Uri uri=data.getData();
try {
//顯示得到的bitmap圖片
Bitmap bm= MediaStore.Images.Media.getBitmap(resolver,uri);
}catch (IOException e){
e.printStackTrace();
}
String[] proj={MediaStore.Images.Media.DATA};
Cursor cursor=managedQuery(uri,proj,null,null,null);
int column_index=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path=cursor.getString(column_index);
Log.e("path>>",path);
return path;
}
//儲存圖片
public void saveBitmap(Context context,Bitmap bmp) {
File appDir = new File(Environment.getExternalStorageDirectory(), "Boohee");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 其次把檔案插入到系統圖庫
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 最後通知相簿更新
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path)));
}
}
主要的自定義控制元件程式碼(魏成林的Android 以任意比例裁剪圖片中的程式碼)
package wz.com.mycut;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.IOException;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
/**
* Created by lenovo on 2018/1/13.
*/
public class SeniorCropImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener,
View.OnLayoutChangeListener {
/* For drawing color field start */
private static final int LINE_COLOR = Color.WHITE;
private static final int OUTER_MASK_COLOR = Color.argb(191, 0, 0, 0);
private static final int LINE_WIDTH_IN_DP = 1;
private final float[] mMatrixValues = new float[9];
protected Matrix mSupportMatrix;
protected ScaleGestureDetector mScaleGestureDetector;
/* For drawing color field end */
protected Paint mPaint;
/*
* 寬比高
*/
protected float mRatio = 1.0f;
protected RectF mCropRect;
//RectFPadding是適應產品需求,給裁剪框mCropRect設定一下padding -- chenglin 2016年04月18日
protected float RectFPadding = 0;
protected int mLastX;
protected int mLastY;
protected OPERATION mOperation;
private onBitmapLoadListener iBitmapLoading = null;
private boolean mEnableDrawCropWidget = true;
/*
For scale and drag
*/
private Matrix mBaseMatrix;
private Matrix mDrawMatrix;
private AccelerateDecelerateInterpolator sInterpolator = new AccelerateDecelerateInterpolator();
private Path mPath;
private int mLineWidth;
private float mScaleMax = 3.0f;
private RectF mBoundaryRect;
private int mRotation = 0;
private int mImageWidth;
private int mImageHeight;
private int mDisplayW;
private int mDisplayH;
public SeniorCropImageView(Context context) {
this(context, null);
}
public SeniorCropImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SeniorCropImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Life_CropImage);
mRatio = a.getFloat(R.styleable.Life_CropImage_life_Crop_ratio, 1.0f);
a.recycle();
}
init();
}
public static void decodeImageForCropping(final String path, final IDecodeCallback callback) {
new Thread(new Runnable() {
@Override
public void run() {
int rotation = 0;
// 讀取一下exif中的rotation
try {
ExifInterface exif = new ExifInterface(path);
final int rotate = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
switch (rotate) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotation = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotation = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
final int textureLimit = getMaxTextureSize();
int scale = 1;
while (options.outWidth / scale >= textureLimit) {
scale *= 2;
}
while (options.outHeight / scale >= textureLimit) {
scale *= 2;
}
options.inSampleSize = scale;
options.inJustDecodeBounds = false;
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeFile(path, options);
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
final Bitmap bimapDecoded = bitmap;
if (bimapDecoded == null) {
return;
}
if (callback != null) {
callback.onDecoded(rotation, bimapDecoded);
}
}
}).start();
}
private static int getMaxTextureSize() {
EGL10 egl = (EGL10) EGLContext.getEGL();
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
// Initialise
int[] version = new int[2];
egl.eglInitialize(display, version);
// Query total number of configurations
int[] totalConfigurations = new int[1];
egl.eglGetConfigs(display, null, 0, totalConfigurations);
// Query actual list configurations
EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations);
int[] textureSize = new int[1];
int maximumTextureSize = 0;
// Iterate through all the configurations to located the maximum texture size
for (int i = 0; i < totalConfigurations[0]; i++) {
// Only need to check for width since opengl textures are always squared
egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize);
// Keep track of the maximum texture size
if (maximumTextureSize < textureSize[0]) {
maximumTextureSize = textureSize[0];
}
}
// Release
egl.eglTerminate(display);
return maximumTextureSize;
}
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
mDisplayW = right - left;
mDisplayH = bottom - top;
if (getDrawable() != null && ((BitmapDrawable) getDrawable()).getBitmap() != null) {
calculateProperties(((BitmapDrawable) getDrawable()).getBitmap());
}
}
private void init() {
mScaleGestureDetector = new ScaleGestureDetector(getContext(), this);
mBaseMatrix = new Matrix();
mDrawMatrix = new Matrix();
mSupportMatrix = new Matrix();
mLineWidth = (int) dipToPixels(LINE_WIDTH_IN_DP);
mPaint = new Paint();
// 表示第一個實線段長dashOnWidth,第一個虛線段長dashOffWidth
mPath = new Path();
mCropRect = new RectF();
mBoundaryRect = new RectF();
setScaleType(ScaleType.MATRIX);
setClickable(true);
}
private float dipToPixels(float dip) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
getResources().getDisplayMetrics());
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
addOnLayoutChangeListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeOnLayoutChangeListener(this);
}
/**
* 設定圖片的裁剪比例,比如3:4就是0.75
*
* @param ratio
*/
public void setCropRatio(final float ratio) {
if (mRatio == ratio) {
return;
}
mRatio = ratio;
//重新選擇比例後,恢復旋轉角度
//setImageRotation(0);
if (getDrawable() == null) {
return;
}
calculateProperties(((BitmapDrawable) getDrawable()).getBitmap());
postInvalidate();
}
public void setImageRotation(int rotation) {
if (mRotation == rotation) {
return;
}
mRotation = rotation;
if (getDrawable() == null) {
return;
}
calculateProperties(((BitmapDrawable) getDrawable()).getBitmap());
postInvalidate();
}
public void setCropRectPadding(float padding) {
RectFPadding = padding;
}
public void setImagePath(final String path) {
//textUtils.isEmpty()判斷是否為空。
if (TextUtils.isEmpty(path)) {
return;
}
if (iBitmapLoading != null) {
Toast.makeText(getContext(),"you Glid框架",Toast.LENGTH_LONG).show();
iBitmapLoading.onLoadPrepare();
}
decodeImageForCropping(path, new IDecodeCallback() {
@Override
public void onDecoded(final int rotation, final Bitmap bitmap) {
post(new Runnable() {
@Override
public void run() {
mRotation = rotation;
setImageBitmap(bitmap);
if (iBitmapLoading != null) {
iBitmapLoading.onLoadFinish();
}
}
});
}
});
}
@Override
public void setImageBitmap(Bitmap bm) {
calculateProperties(bm);
super.setImageBitmap(bm);
}
public void setBitmapLoadingListener(onBitmapLoadListener iBitmapLoad) {
iBitmapLoading = iBitmapLoad;
}
protected void calculateProperties(Bitmap bm) {
mSupportMatrix.reset();
mBaseMatrix.reset();
int widthSize = mDisplayW;
int heightSize = mDisplayH;
generateCropRect(widthSize, heightSize);
mImageWidth = bm.getWidth();
mImageHeight = bm.getHeight();
final boolean rotated = isImageRotated();
final int bitmapWidth = rotated ? mImageHeight : mImageWidth;
final int bitmapHeight = rotated ? mImageWidth : mImageHeight;
mBoundaryRect.set(0, 0, bitmapWidth, bitmapHeight);
final float widthScale = mCropRect.width() / bitmapWidth;
final float heightScale = mCropRect.height() / bitmapHeight;
final float scale = Math.max(widthScale, heightScale);
final float scaledHeight = scale * bitmapHeight;
final float scaledWidth = scale * bitmapWidth;
// 移動到中心點
final int translateX = (int) (mCropRect.left + mCropRect.width() / 2 - scaledWidth / 2);
final int translateY = (int) (mCropRect.top + mCropRect.height() / 2 - scaledHeight / 2);
mBaseMatrix.setScale(scale, scale);
mBaseMatrix.postTranslate(translateX, translateY);
mBaseMatrix.mapRect(mBoundaryRect);
setImageMatrix(getDrawMatrix());
}
private boolean isImageRotated() {
return ((mRotation % 360) == 90) || ((mRotation % 360) == 270);
}
private void generateCropRect(int boundaryWidth, int boundaryHeight) {
//RectFPadding是適應產品需求,給裁剪框mCropRect設定一下padding -- chenglin 2016年04月18日
boundaryWidth = boundaryWidth - (int)(RectFPadding * 2);
boundaryHeight = boundaryHeight - (int)(RectFPadding * 2);
int left;
int top;
int right;
int bottom;
boolean vertical;
// 寬/高 大於比例的話,說明裁剪框是“豎直”的
vertical = (float) boundaryWidth / boundaryHeight > mRatio;
final int rectH = (int) (boundaryWidth / mRatio);
final int rectW = (int) (boundaryHeight * mRatio);
if (vertical) {
left = (boundaryWidth - rectW) / 2;
top = 0;
right = (boundaryWidth + rectW) / 2;
bottom = boundaryHeight;
} else {
left = 0;
top = (boundaryHeight - rectH) / 2;
right = boundaryWidth;
bottom = (boundaryHeight + rectH) / 2;
}
//RectFPadding是適應產品需求,給裁剪框mCropRect設定一下padding -- chenglin 2016年04月18日
mCropRect.set(left + RectFPadding, top + RectFPadding, right + RectFPadding, bottom + RectFPadding);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!mEnableDrawCropWidget) {
return;
}
if (getDrawable() == null) {
return;
}
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setColor(LINE_COLOR);
mPaint.setStrokeWidth(mLineWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPath.reset();
// 上
mPath.moveTo(mCropRect.left, mCropRect.top);
mPath.lineTo(mCropRect.right, mCropRect.top);
// 左
mPath.moveTo(mCropRect.left, mCropRect.top);
mPath.lineTo(mCropRect.left, mCropRect.bottom);
// 右
mPath.moveTo(mCropRect.right, mCropRect.top);
mPath.lineTo(mCropRect.right, mCropRect.bottom);
// 下
mPath.moveTo(mCropRect.right, mCropRect.bottom);
mPath.lineTo(mCropRect.left, mCropRect.bottom);
canvas.drawPath(mPath, mPaint);
// 繪製外部陰影部分
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.parseColor("#B3333333"));
mPaint.setStyle(Paint.Style.FILL);
//下面的四個矩形是裝飾性的,就是裁剪框四周的四個陰影
final int lineOffset = mLineWidth;
if (mCropRect.top > 0) {
canvas.drawRect(0, 0, getMeasuredWidth(), mCropRect.top - lineOffset, mPaint);
}
if (mCropRect.left > 0) {
canvas.drawRect(mCropRect.top - lineOffset - RectFPadding, RectFPadding - lineOffset, mCropRect.left - lineOffset, mCropRect.bottom + lineOffset, mPaint);
}
if (mCropRect.right < getMeasuredWidth()) {
canvas.drawRect(mCropRect.right + lineOffset, mCropRect.top - lineOffset, getMeasuredWidth(), mCropRect.bottom + lineOffset, mPaint);
}
if (mCropRect.bottom < getMeasuredHeight()) {
canvas.drawRect(0, mCropRect.bottom + lineOffset, getMeasuredWidth(), getMeasuredHeight(), mPaint);
}
}
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getPointerCount() > 1) {
mOperation = OPERATION.SCALE;
return mScaleGestureDetector.onTouchEvent(ev);
}
final int action = ev.getActionMasked();
final int x = (int) ev.getX();
final int y = (int) ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
mOperation = OPERATION.DRAG;
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_MOVE:
if (mOperation == OPERATION.DRAG) {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
RectF boundary = getDrawBoundary(getDrawMatrix());
if (boundary.left + deltaX > mCropRect.left) {
deltaX = (int) (mCropRect.left - boundary.left);
} else if (boundary.right + deltaX < mCropRect.right) {
deltaX = (int) (mCropRect.right - boundary.right);
}
if (boundary.top + deltaY > mCropRect.top) {
deltaY = (int) (mCropRect.top - boundary.top);
} else if (boundary.bottom + deltaY < mCropRect.bottom) {
deltaY = (int) (mCropRect.bottom - boundary.bottom);
}
mSupportMatrix.postTranslate(deltaX, deltaY);
setImageMatrix(getDrawMatrix());
mLastX = x;
mLastY = y;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
mLastX = 0;
mLastY = 0;
mOperation = null;
break;
}
return super.onTouchEvent(ev);
}
public Bitmap getOriginBitmap() {
BitmapDrawable drawable = (BitmapDrawable) getDrawable();
return drawable == null ? null : drawable.getBitmap();
}
/**
* 儲存圖片為bitmap
*/
public Bitmap saveCrop() throws OutOfMemoryError {
if (getDrawable() == null) {
return null;
}
Bitmap origin = getOriginBitmap();
Matrix drawMatrix = getDrawMatrix();
// 反轉一下矩陣
Matrix inverse = new Matrix();
drawMatrix.invert(inverse);
// 把裁剪框對應到原圖上去
RectF cropMapped = new RectF();
inverse.mapRect(cropMapped, mCropRect);
clampCropRect(cropMapped, origin.getWidth(), origin.getHeight());
// 如果產生了旋轉,需要一個旋轉矩陣
Matrix rotationM = new Matrix();
if (mRotation % 360 != 0) {
rotationM.postRotate(mRotation, origin.getWidth() / 2, origin.getHeight() / 2);
}
Bitmap cropped = Bitmap.createBitmap(
origin,
(int) cropMapped.left,
(int) cropMapped.top,
(int) cropMapped.width(),
(int) cropMapped.height(),
rotationM, true
);
return cropped;
}
private void clampCropRect(RectF cropRect, int borderW, int borderH) {
if (cropRect.left < 0) {
cropRect.left = 0;
}
if (cropRect.top < 0) {
cropRect.top = 0;
}
if (cropRect.right > borderW) {
cropRect.right = borderW;
}
if (cropRect.bottom > borderH) {
cropRect.bottom = borderH;
}
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
if (scale == 1.0f) {
return true;
}
final float currentScale = getScale(mSupportMatrix);
final float centerX = detector.getFocusX();
final float centerY = detector.getFocusY();
if ((currentScale <= 1.0f && scale < 1.0f)
|| (currentScale >= mScaleMax && scale > 1.0f)) {
return true;
}
if (currentScale * scale < 1.0f) {
scale = 1.0f / currentScale;
} else if (currentScale * scale > mScaleMax) {
scale = mScaleMax / currentScale;
}
mSupportMatrix.postScale(scale, scale, centerX, centerY);
RectF boundary = getDrawBoundary(getDrawMatrix());
float translateX = 0;
if (boundary.left > mCropRect.left) {
translateX = mCropRect.left - boundary.left;
} else if (boundary.right < mCropRect.right) {
translateX = mCropRect.right - boundary.right;
}
Log.d("scale", "x==>" + translateX);
float translateY = 0;
if (boundary.top > mCropRect.top) {
translateY = mCropRect.top - boundary.top;
} else if (boundary.bottom < mCropRect.bottom) {
translateY = mCropRect.bottom - boundary.bottom;
}
mSupportMatrix.postTranslate(translateX, translateY);
setImageMatrix(getDrawMatrix());
return true;
}
protected Matrix getDrawMatrix() {
mDrawMatrix.reset();
if (mRotation % 360 != 0) {
final boolean rotated = isImageRotated();
final int width = rotated ? mImageHeight : mImageWidth;
final int height = rotated ? mImageWidth : mImageHeight;
mDrawMatrix.postRotate(mRotation, mImageWidth / 2, mImageHeight / 2);
if (rotated) {
final int translateX = (width - mImageWidth) / 2;
final int translateY = (height - mImageHeight) / 2;
mDrawMatrix.postTranslate(translateX, translateY);
}
}
mDrawMatrix.postConcat(mBaseMatrix);
mDrawMatrix.postConcat(mSupportMatrix);
return mDrawMatrix;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
final float currentScale = getScale(mSupportMatrix);
if (currentScale < 1.0f) {
Log.e("onScaleEnd", "currentScale==>" + currentScale);
RectF boundary = getDrawBoundary(getDrawMatrix());
post(new AnimatedZoomRunnable(currentScale, 1.0f, boundary.centerX(), boundary.centerY()));
}
}
protected RectF getDrawBoundary(Matrix matrix) {
Drawable drawable = getDrawable();
if (drawable == null) {
return mBoundaryRect;
}
final int bitmapWidth = drawable.getIntrinsicWidth();
final int bitmapHeight = drawable.getIntrinsicHeight();
mBoundaryRect.set(0, 0, bitmapWidth, bitmapHeight);
matrix.mapRect(mBoundaryRect);
return mBoundaryRect;
}
public float getScale(Matrix matrix) {
return (float) Math.sqrt((float) Math.pow(getValue(matrix, Matrix.MSCALE_X), 2) + (float) Math.pow(getValue(matrix, Matrix.MSKEW_Y), 2));
}
/**
* Helper method that 'unpacks' a Matrix and returns the required value
*
* @param matrix - Matrix to unpack
* @param whichValue - Which value from Matrix.M* to return
* @return float - returned value
*/
private float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
public void enableDrawCropWidget(boolean enable) {
mEnableDrawCropWidget = enable;
}
protected enum OPERATION {
DRAG, SCALE
}
public enum Type {
CENTER_CROP, CENTER_INSIDE
}
public interface IDecodeCallback {
void onDecoded(final int rotation, final Bitmap bitmap);
}
//setImagePath這個方法耗時,需要顯示進度條,這個是監聽
public