公司的一个小伙伴写的,可以按照任意比例裁剪图片。我觉得挺好用的。简单在这里记录一下,以后肯定还会用到。
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; imRatio; 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 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.top) { deltaY = (int) (mCropRect.top - boundary.top); } else if (boundary.bottom + deltaY 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 " + translateX); float translateY = 0; if (boundary.top > mCropRect.top) { translateY = mCropRect.top - boundary.top; } else if (boundary.bottom " + 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 interface onBitmapLoadListener { void onLoadPrepare(); void onLoadFinish(); } private class AnimatedZoomRunnable implements Runnable { private final float mFocalX, mFocalY; private final long mStartTime; private final float mZoomStart, mZoomEnd; public AnimatedZoomRunnable(final float currentZoom, final float targetZoom, final float focalX, final float focalY) { mFocalX = focalX; mFocalY = focalY; mStartTime = System.currentTimeMillis(); mZoomStart = currentZoom; mZoomEnd = targetZoom; } @Override public void run() { float t = interpolate(); float scale = mZoomStart + t * (mZoomEnd - mZoomStart); float deltaScale = scale / getScale(mSupportMatrix); mSupportMatrix.postScale(deltaScale, deltaScale, mFocalX, mFocalY); setImageMatrix(getDrawMatrix()); // We haven't hit our target scale yet, so post ourselves again if (t <1f) { postOnAnimation(this); } } private float interpolate() { float t = 1f * (System.currentTimeMillis() - mStartTime) / 200; t = Math.min(1f, t); t = sInterpolator.getInterpolation(t); return t; } } }
1、让这个裁剪框显示图片:
mSeniorImageView.setImagePath(path);
2、保存裁剪后的图片:
Bitmap imageViewBitmap = null; try { imageViewBitmap = mSeniorImageView.saveCrop(); } catch (OutOfMemoryError e) { imageViewBitmap = mSeniorImageView.getOriginBitmap(); PinkToast.makeText(mActivity, R.string.life_image_crop_topbar_crop_error, Toast.LENGTH_LONG).show(); }
3、设置裁剪比例:
mSeniorImageView.setCropRatio(3f / 4f);
4、设置裁剪框的padding:
mSeniorImageView.setCropRectPadding(0f);
5、setImagePath这个方法比较耗时,需要显示进度条,这个是监听:
mSeniorImageView.setBitmapLoadingListener(new SeniorCropImageView.onBitmapLoadListener() { @Override public void onLoadPrepare() { mActivity.showProgress(); } @Override public void onLoadFinish() { mActivity.hideProgress(); } });
以上所述是小编给大家带来的Android 以任意比例裁剪图片代码分享,希望对大家有所帮助