公司的一个小伙伴写的,可以按照任意比例裁剪图片。我觉得挺好用的。简单在这里记录一下,以后肯定还会用到。
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); 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,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,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) { if (TextUtils.isEmpty(path)) { return; } if (iBitmapLoading != null) { 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,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.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,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,mPaint); } if (mCropRect.bottom < getMeasuredHeight()) { canvas.drawRect(0,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,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; } } } <declare-styleable name="life_CropImage"> <attr name="life_Crop_ratio" format="float" /> <attr name="life_Crop_scale_type" format="enum"> <enum name="life_center_crop" value="0" /> <enum name="life_center_insIDe" value="1" /> </attr> </declare-styleable>
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 以任意比例裁剪图片代码分享,希望对大家有所帮助
总结以上是内存溢出为你收集整理的Android 以任意比例裁剪图片代码分享全部内容,希望文章能够帮你解决Android 以任意比例裁剪图片代码分享所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)