package com.netease.nim.uikit.common.ui.imageview; 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.Rect; import android.os.SystemClock; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import com.netease.nim.uikit.common.util.file.AttachmentStore; import java.io.ByteArrayOutputStream; import java.io.IOException; public class CropImageView extends MultiTouchZoomableImageView { private static final int MARGIN = 50; private int outputX; private int outputY; Paint shadowPaint; Paint linePaint; private Rect drawRect; private Rect selection; // Programatic entry point public CropImageView(Context context) { super(context); initCropImageView(context); } // XML entry point public CropImageView(Context context, AttributeSet attrs) { super(context, attrs); initCropImageView(context); } protected void initCropImageView(Context context) { shadowPaint = new Paint(); shadowPaint.setColor(Color.argb((int) (255 * 0.6), 0, 0, 0)); linePaint = new Paint(); linePaint.setColor(Color.rgb(0x99, 0x99, 0x99)); drawRect = new Rect(); transIgnoreScale = true; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (changed) { selection = updateSelection(); } } public void setOutput(int outputX, int outputY) { this.outputX = outputX; this.outputY = outputY; } public byte[] getCroppedImage() { Bitmap cropped = getCroppedBitmap(); if (cropped == null) { return null; } ByteArrayOutputStream stream = new ByteArrayOutputStream(); cropped.compress(Bitmap.CompressFormat.JPEG, 90, stream); if (cropped != mBitmap) { cropped.recycle(); } byte[] data = stream.toByteArray(); try { stream.close(); } catch (IOException e) { e.printStackTrace(); } return data; } public boolean saveCroppedIamge(String path) { Bitmap cropped = getCroppedBitmap(); return AttachmentStore.saveBitmap(cropped, path, cropped != mBitmap); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (selection != null) { canvas.drawLine(selection.left, selection.top, selection.right, selection.top, linePaint); canvas.drawLine(selection.left, selection.top, selection.left, selection.bottom, linePaint); canvas.drawLine(selection.right, selection.top, selection.right, selection.bottom, linePaint); canvas.drawLine(selection.left, selection.bottom, selection.right, selection.bottom, linePaint); drawRect.set(0, 0, getRight(), selection.top); canvas.drawRect(drawRect, shadowPaint); drawRect.set(0, selection.top, selection.left, selection.bottom); canvas.drawRect(drawRect, shadowPaint); drawRect.set(selection.right, selection.top, getRight(), selection.bottom); canvas.drawRect(drawRect, shadowPaint); drawRect.set(0, selection.bottom, getRight(), getBottom()); canvas.drawRect(drawRect, shadowPaint); } } @Override protected Rect updateSelection() { if (outputX <= 0 || outputY <= 0) { return null; } Rect selection; int viewWidth = getWidth(); int viewHeight = getHeight(); float outputRatio = ((float)outputY) / outputX; float screenRatio = ((float)viewHeight) / viewWidth; if (outputRatio < screenRatio) { int width = viewWidth - MARGIN * 2; int height = outputY * width / outputX; int x = MARGIN; int y = (viewHeight - height) / 2; selection = new Rect(x, y, x + width, y + height); } else { int height = viewHeight - MARGIN * 2; int width = outputX * height / outputY; int y = MARGIN; int x = (viewWidth - width) / 2; selection = new Rect(x, y, x + width, y + height); } return selection; } private Bitmap getCroppedBitmap() { Bitmap bitmap = getImageBitmap(); if (bitmap == null) { return null; } if (selection == null) { return bitmap; } Matrix matrix = getImageViewMatrix(); float transX = getValue(matrix, Matrix.MTRANS_X); float transY = getValue(matrix, Matrix.MTRANS_Y); float scale = getValue(matrix, Matrix.MSCALE_X); int x = (int) ((selection.left - transX) / scale); int y = (int) ((selection.top - transY) / scale) ; int width = (int) (selection.width() / scale); int height = (int) (selection.height() / scale); // 边界判断 x = (x >= 0 ? x : 0); y = (y >= 0 ? y : 0); width = (width <= bitmap.getWidth() - x ? width : bitmap.getWidth() - x); height = (height <= bitmap.getHeight() - y ? height : bitmap.getHeight() - y); // 保持长宽比 float outputRatio = ((float)outputY) / outputX; float screenRatio = ((float)height) / width; if (outputRatio < screenRatio) { height = (int) (width * outputRatio); } else { width = (int) (height / outputRatio); } Matrix m = new Matrix(); final float sx = outputX / (float)width; m.setScale(sx, sx); try{ return Bitmap.createBitmap(bitmap, x, y, width, height, m, false); }catch(Exception e){ return null; } } @Override protected void center(boolean vertical, boolean horizontal, boolean animate) { if (mBitmap == null) return; if (selection == null) { invalidate(); return; } Matrix m = getImageViewMatrix(); float [] topLeft = new float[] { 0, 0 }; float [] botRight = new float[] { mBitmap.getWidth(), mBitmap.getHeight() }; translatePoint(m, topLeft); translatePoint(m, botRight); float deltaX = 0, deltaY = 0; if (vertical) { if (topLeft[1] > selection.bottom) { deltaY = selection.bottom - topLeft[1]; } else if (botRight[1] < selection.top) { deltaY = selection.top - botRight[1]; } } if (horizontal) { if (topLeft[0] > selection.right) { deltaX = selection.right - topLeft[0]; } else if (botRight[0] < selection.left) { deltaX = selection.left - botRight[0]; } } postTranslate(deltaX, deltaY); if (animate) { Animation a = new TranslateAnimation(-deltaX, 0, -deltaY, 0); a.setStartTime(SystemClock.elapsedRealtime()); a.setDuration(250); setAnimation(a); } setImageMatrix(getImageViewMatrix()); } @Override public boolean onTouchEvent(MotionEvent event) { boolean handled = super.onTouchEvent(event); if(mBitmap!=null) { if(event.getAction() == MotionEvent.ACTION_UP) { if (fling()) { if (checkImagePosition(false)) { stopFling(); } } else { checkImagePosition(true); } } } return handled; } // Sets the bitmap for the image and resets the base public void setImageBitmap(final Bitmap bitmap) { super.setImageBitmap(bitmap, selection); } /** * * 把图片移动回到截屏的矩形框内,保证图片能完全覆盖截屏矩形 * @date 2014年5月22日 * @return */ protected boolean checkImagePosition(boolean scroll) { boolean translate = false; if(mBitmap == null || selection == null){ return translate; } Matrix m = getImageViewMatrix(); float [] topLeft = new float[] { 0, 0 }; float [] botRight = new float[] { mBitmap.getWidth(), mBitmap.getHeight() }; translatePoint(m, topLeft); translatePoint(m, botRight); float transX = 0.0f; float transY = 0.0f; if(topLeft[0] > selection.left){ transX = selection.left - topLeft[0]; translate = true; }else if(botRight[0] < selection.right){ transX = selection.right - botRight[0]; translate = true; } if(topLeft[1] > selection.top){ transY = selection.top - topLeft[1]; translate = true; }else if(botRight[1] < selection.bottom){ transY = selection.bottom - botRight[1]; translate = true; } if(scroll && translate){ //直线动画的效果移回 scrollBy(transX, transY, 200); } return translate; } @Override protected void onScrollFinish() { checkImagePosition(true); } }