图片从手机的图库中获取或者直接通过相机拍摄获得,获得图片后利用工具类对图片进行裁剪,为了防止内存溢出。
图片裁剪的工具类:CropImageActivity.java
package com.example.cropimage
图片裁剪的工具类:CropImageActivity.java
package com.example.cropimage
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
/**
* 裁剪界面
*
*/
public class CropImageActivity extends Activity implements OnClickListener{
private CropImageView mImageView;
private Bitmap mBitmap;
private CropImage mCrop;
private Button mSave;
private Button mCancel,rotateLeft,rotateRight;
private String mPath = "CropImageActivity";
private String TAG = "";
public int screenWidth = 0;
public int screenHeight = 0;
private ProgressBar mProgressBar;
public static final int SHOW_PROGRESS = 2000;
public static final int REMOVE_PROGRESS = 2001;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_PROGRESS:
mProgressBar.setVisibility(View.VISIBLE);
break;
case REMOVE_PROGRESS:
mHandler.removeMessages(SHOW_PROGRESS);
mProgressBar.setVisibility(View.INVISIBLE);
break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gl_modify_avatar);
init();
}
@Override
protected void onStop(){
super.onStop();
if(mBitmap!=null){
mBitmap=null;
}
}
private void init()
{
getWindowWH();
mPath = getIntent().getStringExtra("path");
Log.i(TAG, "得到的图片的路径是 = " + mPath);
mImageView = (CropImageView) findViewById(R.id.gl_modify_avatar_image);
mSave = (Button) this.findViewById(R.id.gl_modify_avatar_save);
mCancel = (Button) this.findViewById(R.id.gl_modify_avatar_cancel);
rotateLeft = (Button) this.findViewById(R.id.gl_modify_avatar_rotate_left);
rotateRight = (Button) this.findViewById(R.id.gl_modify_avatar_rotate_right);
mSave.setOnClickListener(this);
mCancel.setOnClickListener(this);
rotateLeft.setOnClickListener(this);
rotateRight.setOnClickListener(this);
try{
mBitmap = createBitmap(mPath,screenWidth,screenHeight);
if(mBitmap==null){
Toast.makeText(CropImageActivity.this, CropImageActivity.this.getResources().getString(R.string.app_can_not_find_pic), 0).show();
finish();
}else{
resetImageView(mBitmap);
}
}catch (Exception e) {
Toast.makeText(CropImageActivity.this, CropImageActivity.this.getResources().getString(R.string.app_can_not_find_pic), 0).show();
finish();
}
addProgressbar();
}
/**
* 获取屏幕的高和宽
*/
private void getWindowWH(){
DisplayMetrics dm=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
screenWidth=dm.widthPixels;
screenHeight=dm.heightPixels;
}
private void resetImageView(Bitmap b){
mImageView.clear();
mImageView.setImageBitmap(b);
mImageView.setImageBitmapResetBase(b, true);
mCrop = new CropImage(this, mImageView,mHandler);
mCrop.crop(b);
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.gl_modify_avatar_cancel:
// mCrop.cropCancel();
finish();
break;
case R.id.gl_modify_avatar_save:
String path = mCrop.saveToLocal(mCrop.cropAndSave());
Log.i(TAG, "截取后图片的路径是 = " + path);
Intent intent = new Intent();
intent.putExtra("path", path);
setResult(RESULT_OK, intent);
finish();
break;
case R.id.gl_modify_avatar_rotate_left:
mCrop.startRotate(270.f);
break;
case R.id.gl_modify_avatar_rotate_right:
mCrop.startRotate(90.f);
break;
}
}
protected void addProgressbar() {
mProgressBar = new ProgressBar(this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
addContentView(mProgressBar, params);
mProgressBar.setVisibility(View.INVISIBLE);
}
public Bitmap createBitmap(String path,int w,int h){
try{
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
// 这里是整个方法的关键,inJustDecodeBounds设为true时将不为图片分配内存。
BitmapFactory.decodeFile(path, opts);
int srcWidth = opts.outWidth;// 获取图片的原始宽度
int srcHeight = opts.outHeight;// 获取图片原始高度
int destWidth = 0;
int destHeight = 0;
// 缩放的比例
double ratio = 0.0;
if (srcWidth < w || srcHeight < h) {
ratio = 0.0;
destWidth = srcWidth;
destHeight = srcHeight;
} else if (srcWidth > srcHeight) {// 按比例计算缩放后的图片大小,maxLength是长或宽允许的最大长度
ratio = (double) srcWidth / w;
destWidth = w;
destHeight = (int) (srcHeight / ratio);
} else {
ratio = (double) srcHeight / h;
destHeight = h;
destWidth = (int) (srcWidth / ratio);
}
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 缩放的比例,缩放是很难按准备的比例进行缩放的,目前我只发现只能通过inSampleSize来进行缩放,其值表明缩放的倍数,SDK中建议其值是2的指数值
newOpts.inSampleSize = (int) ratio + 1;
// inJustDecodeBounds设为false表示把图片读进内存中
newOpts.inJustDecodeBounds = false;
// 设置大小,这个一般是不准确的,是以inSampleSize的为准,但是如果不设置却不能缩放
newOpts.outHeight = destHeight;
newOpts.outWidth = destWidth;
// 获取缩放后图片
return BitmapFactory.decodeFile(path, newOpts);
} catch (Exception e) {
// TODO: handle exception
return null;
}
}
}
CropImage.java
CropImageView.java
ImageViewTouchBase.java
从相册中获取图片:
在Activity回调中:对不同来源的图片进行处理,先交给裁剪工具,裁剪完后再将图片拿来使用
if (requestCode == FLAG_CHOOSE_IMG && resultCode == RESULT_OK) {
CropImage.java
package com.example.corpimage
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import cn.leature.istarbaby.R;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.media.FaceDetector;
import android.os.Environment;
import android.os.Handler;
/**
* 裁剪处理
*
*/
public class CropImage {
public static final File FILE_SDCARD = Environment
.getExternalStorageDirectory();
public static final File FILE_LOCAL = new File(FILE_SDCARD, "weixin");
private static final int CroppedImageWH = 400;
public boolean mWaitingToPick; // Whether we are wait the user to pick a
// face.
public boolean mSaving; // Whether the "save" button is already clicked.
public HighlightView mCrop;
private Context mContext;
private Handler mHandler;
private CropImageView mImageView;
private Bitmap mBitmap;
public CropImage(Context context, CropImageView imageView, Handler handler) {
mContext = context;
mImageView = imageView;
mImageView.setCropImage(this);
mHandler = handler;
}
/**
* 图片裁剪
*/
public void crop(Bitmap bm) {
mBitmap = bm;
startFaceDetection();
}
public void startRotate(float d) {
if (((Activity) mContext).isFinishing()) {
return;
}
final float degrees = d;
showProgressDialog(mContext.getResources().getString(R.string.gl_wait),
new Runnable() {
@Override
public void run() {
final CountDownLatch latch = new CountDownLatch(1);
mHandler.post(new Runnable() {
@Override
public void run() {
try {
Matrix m = new Matrix();
m.setRotate(degrees);
Bitmap tb = Bitmap.createBitmap(mBitmap, 0,
0, mBitmap.getWidth(),
mBitmap.getHeight(), m, false);
mBitmap = tb;
mImageView.resetView(tb);
if (mImageView.mHighlightViews.size() > 0) {
mCrop = mImageView.mHighlightViews
.get(0);
mCrop.setFocus(true);
}
} catch (Exception e) {
// TODO: handle exception
}
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// mRunFaceDetection.run();
}
}, mHandler);
}
private void startFaceDetection() {
if (((Activity) mContext).isFinishing()) {
return;
}
showProgressDialog(mContext.getResources().getString(R.string.gl_wait),
new Runnable() {
@Override
public void run() {
final CountDownLatch latch = new CountDownLatch(1);
final Bitmap b = mBitmap;
mHandler.post(new Runnable() {
@Override
public void run() {
if (b != mBitmap && b != null) {
mImageView.setImageBitmapResetBase(b, true);
mBitmap.recycle();
mBitmap = b;
}
if (mImageView.getScale() == 1.0f) {
mImageView.center(true, true);
}
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
mRunFaceDetection.run();
}
}, mHandler);
}
/**
* 裁剪并保存
*
* @return
*/
public Bitmap cropAndSave() {
final Bitmap bmp = onSaveClicked(mBitmap);
mImageView.mHighlightViews.clear();
return bmp;
}
/**
* 裁剪并保存
*
* @return
*/
public Bitmap cropAndSave(Bitmap bm) {
final Bitmap bmp = onSaveClicked(bm);
mImageView.mHighlightViews.clear();
return bmp;
}
/**
* 取消裁剪
*/
public void cropCancel() {
mImageView.mHighlightViews.clear();
mImageView.invalidate();
}
private Bitmap onSaveClicked(Bitmap bm) {
// CR: TODO!
// TODO this code needs to change to use the decode/crop/encode single
// step api so that we don't require that the whole (possibly large)
// bitmap doesn't have to be read into memory
if (mSaving)
return bm;
if (mCrop == null) {
return bm;
}
mSaving = true;
Rect r = mCrop.getCropRect();
// int width = r.width(); // CR: final == happy panda!
// int height = r.height();
// If we are circle cropping, we want alpha channel, which is the
// third param here.
// Bitmap croppedImage = Bitmap.createBitmap(width, height,
// Bitmap.Config.RGB_565);
// {
// Canvas canvas = new Canvas(croppedImage);
// Rect dstRect = new Rect(0, 0, width, height);
// canvas.drawBitmap(bm, r, dstRect, null);
// }
// Rect dr = mCrop.mDrawRect;
int width = CroppedImageWH; // dr.width(); // modify by yc
int height = CroppedImageWH; // dr.height();
Bitmap croppedImage = Bitmap.createBitmap(width, height,
Bitmap.Config.RGB_565);
{
Canvas canvas = new Canvas(croppedImage);
Rect dstRect = new Rect(0, 0, width, height);
canvas.drawBitmap(bm, r, dstRect, null);
}
return croppedImage;
}
public String saveToLocal(Bitmap bm) {
String path = FILE_LOCAL + "mm.jpg";
try {
FileOutputStream fos = new FileOutputStream(path);
bm.compress(CompressFormat.JPEG, 75, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return path;
}
private void showProgressDialog(String msg, Runnable job, Handler handler) {
// final ProgressDialog progress = ProgressDialog.show(mContext, null,
// msg);
// new Thread(new BackgroundJob(progress, job, handler)).start();
new Thread(new BackgroundJob(msg, job, handler)).start();
}
Runnable mRunFaceDetection = new Runnable() {
float mScale = 1F;
Matrix mImageMatrix;
FaceDetector.Face[] mFaces = new FaceDetector.Face[3];
int mNumFaces;
// For each face, we create a HightlightView for it.
private void handleFace(FaceDetector.Face f) {
PointF midPoint = new PointF();
int r = ((int) (f.eyesDistance() * mScale)) * 2;
f.getMidPoint(midPoint);
midPoint.x *= mScale;
midPoint.y *= mScale;
int midX = (int) midPoint.x;
int midY = (int) midPoint.y;
HighlightView hv = new HighlightView(mImageView);
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Rect imageRect = new Rect(0, 0, width, height);
RectF faceRect = new RectF(midX, midY, midX, midY);
faceRect.inset(-r, -r);
if (faceRect.left < 0) {
faceRect.inset(-faceRect.left, -faceRect.left);
}
if (faceRect.top < 0) {
faceRect.inset(-faceRect.top, -faceRect.top);
}
if (faceRect.right > imageRect.right) {
faceRect.inset(faceRect.right - imageRect.right, faceRect.right
- imageRect.right);
}
if (faceRect.bottom > imageRect.bottom) {
faceRect.inset(faceRect.bottom - imageRect.bottom,
faceRect.bottom - imageRect.bottom);
}
hv.setup(mImageMatrix, imageRect, faceRect, false, true);
mImageView.add(hv);
}
// Create a default HightlightView if we found no face in the picture.
private void makeDefault() {
HighlightView hv = new HighlightView(mImageView);
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Rect imageRect = new Rect(0, 0, width, height);
// CR: sentences!
// make the default size about 4/5 of the width or height
int cropWidth = Math.min(width, height) * 4 / 5;
int cropHeight = cropWidth;
int x = (width - cropWidth) / 2;
int y = (height - cropHeight) / 2;
RectF cropRect = new RectF(x, y, x + cropWidth, y + cropHeight);
hv.setup(mImageMatrix, imageRect, cropRect, false, true);
mImageView.add(hv);
}
// Scale the image down for faster face detection.
private Bitmap prepareBitmap() {
if (mBitmap == null) {
return null;
}
// 256 pixels wide is enough.
if (mBitmap.getWidth() > 256) {
mScale = 256.0F / mBitmap.getWidth(); // CR: F => f (or change
// all f to F).
}
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
Bitmap faceBitmap = Bitmap.createBitmap(mBitmap, 0, 0,
mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
return faceBitmap;
}
@Override
public void run() {
mImageMatrix = mImageView.getImageMatrix();
Bitmap faceBitmap = prepareBitmap();
mScale = 1.0F / mScale;
if (faceBitmap != null) {
FaceDetector detector = new FaceDetector(faceBitmap.getWidth(),
faceBitmap.getHeight(), mFaces.length);
mNumFaces = detector.findFaces(faceBitmap, mFaces);
}
if (faceBitmap != null && faceBitmap != mBitmap) {
faceBitmap.recycle();
}
mHandler.post(new Runnable() {
@Override
public void run() {
mWaitingToPick = mNumFaces > 1;
// if (mNumFaces > 0) {
// // for (int i = 0; i < mNumFaces; i++) {
// for (int i = 0; i < 1; i++) {
// handleFace(mFaces[i]);
// }
// } else {
makeDefault();
// }
mImageView.invalidate();
if (mImageView.mHighlightViews.size() > 0) {
mCrop = mImageView.mHighlightViews.get(0);
mCrop.setFocus(true);
}
if (mNumFaces > 1) {
// CR: no need for the variable t. just do
// Toast.makeText(...).show().
// Toast t = Toast.makeText(mContext,
// R.string.multiface_crop_help, Toast.LENGTH_SHORT);
// t.show();
}
}
});
}
};
class BackgroundJob implements Runnable {
// private ProgressDialog mProgress;
private String message;
private Runnable mJob;
private Handler mHandler;
// public BackgroundJob(ProgressDialog progress, Runnable job, Handler
// handler)
// {
// mProgress = progress;
// mJob = job;
// mHandler = handler;
// }
public BackgroundJob(String m, Runnable job, Handler handler) {
message = m;
mJob = job;
mHandler = handler;
// mProgress = new ProgressDialog(mContext);
// mProgress.setMessage(message);
// mProgress.show();
}
@Override
public void run() {
final CountDownLatch latch = new CountDownLatch(1);
mHandler.post(new Runnable() {
@Override
public void run() {
try {
mHandler.sendMessage(mHandler
.obtainMessage(CropImageActivity.SHOW_PROGRESS));
// if (mProgress != null && !mProgress.isShowing())
// {
// mProgress.show();
// }
} catch (Exception e) {
// TODO: handle exception
}
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
mJob.run();
} finally {
mHandler.sendMessage(mHandler
.obtainMessage(CropImageActivity.REMOVE_PROGRESS));
// mHandler.post(new Runnable()
// {
// public void run()
// {
// if (mProgress != null && mProgress.isShowing())
// {
// mProgress.dismiss();
// mProgress = null;
// }
// }
// });
}
}
}
}
CropImageView.java
package cn.leature.istarbaby.info;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class CropImageView extends ImageViewTouchBase {
public ArrayList<HighlightView> mHighlightViews = new ArrayList<HighlightView>();
HighlightView mMotionHighlightView = null;
float mLastX, mLastY;
int mMotionEdge;
private CropImage mCropImage;
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mBitmapDisplayed.getBitmap() != null) {
for (HighlightView hv : mHighlightViews) {
hv.mMatrix.set(getImageMatrix());
hv.invalidate();
if (hv.mIsFocused) {
centerBasedOnHighlightView(hv);
}
}
}
}
public CropImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void zoomTo(float scale, float centerX, float centerY) {
super.zoomTo(scale, centerX, centerY);
for (HighlightView hv : mHighlightViews) {
hv.mMatrix.set(getImageMatrix());
hv.invalidate();
}
}
@Override
protected void zoomIn() {
super.zoomIn();
for (HighlightView hv : mHighlightViews) {
hv.mMatrix.set(getImageMatrix());
hv.invalidate();
}
}
@Override
protected void zoomOut() {
super.zoomOut();
for (HighlightView hv : mHighlightViews) {
hv.mMatrix.set(getImageMatrix());
hv.invalidate();
}
}
@Override
protected void postTranslate(float deltaX, float deltaY) {
super.postTranslate(deltaX, deltaY);
for (int i = 0; i < mHighlightViews.size(); i++) {
HighlightView hv = mHighlightViews.get(i);
hv.mMatrix.postTranslate(deltaX, deltaY);
hv.invalidate();
}
}
// According to the event's position, change the focus to the first
// hitting cropping rectangle.
private void recomputeFocus(MotionEvent event) {
for (int i = 0; i < mHighlightViews.size(); i++) {
HighlightView hv = mHighlightViews.get(i);
hv.setFocus(false);
hv.invalidate();
}
for (int i = 0; i < mHighlightViews.size(); i++) {
HighlightView hv = mHighlightViews.get(i);
int edge = hv.getHit(event.getX(), event.getY());
if (edge != HighlightView.GROW_NONE) {
if (!hv.hasFocus()) {
hv.setFocus(true);
hv.invalidate();
}
break;
}
}
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
CropImage cropImage = mCropImage;
if (cropImage.mSaving) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: // CR: inline case blocks.
if (cropImage.mWaitingToPick) {
recomputeFocus(event);
} else {
for (int i = 0; i < mHighlightViews.size(); i++) { // CR:
// iterator
// for; if
// not, then
// i++ =>
// ++i.
HighlightView hv = mHighlightViews.get(i);
int edge = hv.getHit(event.getX(), event.getY());
if (edge != HighlightView.GROW_NONE) {
mMotionEdge = edge;
mMotionHighlightView = hv;
mLastX = event.getX();
mLastY = event.getY();
// CR: get rid of the extraneous parens below.
mMotionHighlightView.setMode((edge == HighlightView.MOVE) ? HighlightView.ModifyMode.Move
: HighlightView.ModifyMode.Grow);
break;
}
}
}
break;
// CR: vertical space before case blocks.
case MotionEvent.ACTION_UP:
if (cropImage.mWaitingToPick) {
for (int i = 0; i < mHighlightViews.size(); i++) {
HighlightView hv = mHighlightViews.get(i);
if (hv.hasFocus()) {
cropImage.mCrop = hv;
for (int j = 0; j < mHighlightViews.size(); j++) {
if (j == i) { // CR: if j != i do your shit; no need
// for continue.
continue;
}
mHighlightViews.get(j).setHidden(true);
}
centerBasedOnHighlightView(hv);
mCropImage.mWaitingToPick = false;
return true;
}
}
} else if (mMotionHighlightView != null) {
centerBasedOnHighlightView(mMotionHighlightView);
mMotionHighlightView.setMode(HighlightView.ModifyMode.None);
}
mMotionHighlightView = null;
break;
case MotionEvent.ACTION_MOVE:
if (cropImage.mWaitingToPick) {
recomputeFocus(event);
} else if (mMotionHighlightView != null) {
mMotionHighlightView.handleMotion(mMotionEdge, event.getX() - mLastX, event.getY() - mLastY);
mLastX = event.getX();
mLastY = event.getY();
if (true) {
// This section of code is optional. It has some user
// benefit in that moving the crop rectangle against
// the edge of the screen causes scrolling but it means
// that the crop rectangle is no longer fixed under
// the user's finger.
ensureVisible(mMotionHighlightView);
}
}
break;
}
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
center(true, true);
break;
case MotionEvent.ACTION_MOVE:
// if we're not zoomed then there's no point in even allowing
// the user to move the image around. This call to center puts
// it back to the normalized location (with false meaning don't
// animate).
// if (getScale() == 1F) {
center(true, true);
// }
break;
}
return true;
}
// Pan the displayed image to make sure the cropping rectangle is visible.
private void ensureVisible(HighlightView hv) {
Rect r = hv.mDrawRect;
int panDeltaX1 = Math.max(0, getLeft() - r.left);
int panDeltaX2 = Math.min(0, getRight() - r.right);
int panDeltaY1 = Math.max(0, getTop() - r.top);
int panDeltaY2 = Math.min(0, getBottom() - r.bottom);
int panDeltaX = panDeltaX1 != 0 ? panDeltaX1 : panDeltaX2;
int panDeltaY = panDeltaY1 != 0 ? panDeltaY1 : panDeltaY2;
if (panDeltaX != 0 || panDeltaY != 0) {
panBy(panDeltaX, panDeltaY);
}
}
// If the cropping rectangle's size changed significantly, change the
// view's center and scale according to the cropping rectangle.
//hv.mDrawRect.width<0.54*thisWidth||width>0.66*thisWidth,need to zoom
private void centerBasedOnHighlightView(HighlightView hv) {
Rect drawRect = hv.mDrawRect;
float width = drawRect.width();
float height = drawRect.height();
float thisWidth = getWidth();
float thisHeight = getHeight();
float z1 = thisWidth / width * .6F;
float z2 = thisHeight / height * .6F;
float zoom = Math.min(z1, z2);
zoom = zoom * this.getScale();
zoom = Math.max(1F, zoom);//assure getScale()>1
if ((Math.abs(zoom - getScale()) / zoom) > 0.1) {
float[] coordinates = new float[] { hv.mCropRect.centerX(), hv.mCropRect.centerY() };
getImageMatrix().mapPoints(coordinates);
zoomTo(zoom, coordinates[0], coordinates[1], 300F); // CR: 300.0f.
}
ensureVisible(hv);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < mHighlightViews.size(); i++) {
mHighlightViews.get(i).draw(canvas);
}
}
public void add(HighlightView hv) {
mHighlightViews.clear();
mHighlightViews.add(hv);
invalidate();
}
public void setCropImage(CropImage cropImage)
{
mCropImage = cropImage;
}
public void resetView(Bitmap b){
setImageBitmap(b);
setImageBitmapResetBase(b, true);
setImageMatrix(getImageViewMatrix());
int width = mBitmapDisplayed.getWidth();
int height = mBitmapDisplayed.getHeight();
Rect imageRect = new Rect(0, 0, width, height);
int cropWidth = Math.min(width, height) * 4 / 5;
int cropHeight = cropWidth;
int x = (width - cropWidth) / 2;
int y = (height - cropHeight) / 2;
RectF cropRect = new RectF(x, y, x + cropWidth, y + cropHeight);
HighlightView hv = new HighlightView(this);
hv.setup(getImageViewMatrix(), imageRect, cropRect, false, true);
hv.setFocus(true);
add(hv);
centerBasedOnHighlightView(hv);
hv.setMode(HighlightView.ModifyMode.None);
center(true, true);
invalidate();
}
}
package cn.leature.istarbaby.info;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.ImageView;
public abstract class ImageViewTouchBase extends ImageView {
@SuppressWarnings("unused")
private static final String TAG = "ImageViewTouchBase";
// This is the base transformation which is used to show the image
// initially. The current computation for this shows the image in
// it's entirety, letterboxing as needed. One could choose to
// show the image as cropped instead.
//
// This matrix is recomputed when we go from the thumbnail image to
// the full size image.
protected Matrix mBaseMatrix = new Matrix();
// This is the supplementary transformation which reflects what
// the user has done in terms of zooming and panning.
//
// This matrix remains the same when we go from the thumbnail image
// to the full size image.
protected Matrix mSuppMatrix = new Matrix();
// This is the final matrix which is computed as the concatentation
// of the base matrix and the supplementary matrix.
private final Matrix mDisplayMatrix = new Matrix();
// Temporary buffer used for getting the values out of a matrix.
private final float[] mMatrixValues = new float[9];
// The current bitmap being displayed.
final public RotateBitmap mBitmapDisplayed = new RotateBitmap(null);
int mThisWidth = -1, mThisHeight = -1;
float mMaxZoom;
/**
* 高亮状态
*/
public static final int STATE_HIGHLIGHT = 0x0;
/**
* 涂鸦状态
*/
public static final int STATE_DOODLE = STATE_HIGHLIGHT + 1;
/**
* 没有任何操作
*/
public static final int STATE_NONE = STATE_HIGHLIGHT + 2;
protected int mState = STATE_HIGHLIGHT;
// ImageViewTouchBase will pass a Bitmap to the Recycler if it has finished
// its use of that Bitmap.
public interface Recycler {
public void recycle(Bitmap b);
}
public void setRecycler(Recycler r) {
mRecycler = r;
}
private Recycler mRecycler;
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mThisWidth = right - left;
mThisHeight = bottom - top;
Runnable r = mOnLayoutRunnable;
if (r != null) {
mOnLayoutRunnable = null;
r.run();
}
if (mBitmapDisplayed.getBitmap() != null) {
getProperBaseMatrix(mBitmapDisplayed, mBaseMatrix);
setImageMatrix(getImageViewMatrix());
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && getScale() > 1.0f) {
// If we're zoomed in, pressing Back jumps out to show the entire
// image, otherwise Back returns the user to the gallery.
zoomTo(1.0f);
return true;
}
return super.onKeyDown(keyCode, event);
}
protected Handler mHandler = new Handler();
protected int mLastXTouchPos;
protected int mLastYTouchPos;
@Override
public void setImageBitmap(Bitmap bitmap) {
setImageBitmap(bitmap, 0);
}
private void setImageBitmap(Bitmap bitmap, int rotation) {
super.setImageBitmap(bitmap);
Drawable d = getDrawable();
if (d != null) {
d.setDither(true);
}
Bitmap old = mBitmapDisplayed.getBitmap();
mBitmapDisplayed.setBitmap(bitmap);
mBitmapDisplayed.setRotation(rotation);
if (old != null && old != bitmap && mRecycler != null) {
mRecycler.recycle(old);
}
}
public void clear() {
setImageBitmapResetBase(null, true);
}
private Runnable mOnLayoutRunnable = null;
// This function changes bitmap, reset base matrix according to the size
// of the bitmap, and optionally reset the supplementary matrix.
public void setImageBitmapResetBase(final Bitmap bitmap, final boolean resetSupp) {
setImageRotateBitmapResetBase(new RotateBitmap(bitmap), resetSupp);
}
public void setImageRotateBitmapResetBase(final RotateBitmap bitmap, final boolean resetSupp) {
final int viewWidth = getWidth();
if (viewWidth <= 0) {
mOnLayoutRunnable = new Runnable() {
@Override
public void run() {
setImageRotateBitmapResetBase(bitmap, resetSupp);
}
};
return;
}
if (bitmap.getBitmap() != null) {
getProperBaseMatrix(bitmap, mBaseMatrix);
setImageBitmap(bitmap.getBitmap(), bitmap.getRotation());
} else {
mBaseMatrix.reset();
setImageBitmap(null);
}
if (resetSupp) {
mSuppMatrix.reset();
}
setImageMatrix(getImageViewMatrix());
mMaxZoom = maxZoom();
}
// Center as much as possible in one or both axis. Centering is
// defined as follows: if the image is scaled down below the
// view's dimensions then center it (literally). If the image
// is scaled larger than the view and is translated out of view
// then translate it back into view (i.e. eliminate black bars).
public void center(boolean horizontal, boolean vertical) {
if (mBitmapDisplayed.getBitmap() == null) {
return;
}
Matrix m = getImageViewMatrix();
RectF rect = new RectF(0, 0, mBitmapDisplayed.getBitmap().getWidth(), mBitmapDisplayed.getBitmap().getHeight());
m.mapRect(rect);
float height = rect.height();
float width = rect.width();
float deltaX = 0, deltaY = 0;
if (vertical) {
int viewHeight = getHeight();
if (height < viewHeight) {
deltaY = (viewHeight - height) / 2 - rect.top;
} else if (rect.top > 0) {
deltaY = -rect.top;
} else if (rect.bottom < viewHeight) {
deltaY = getHeight() - rect.bottom;
}
}
if (horizontal) {
int viewWidth = getWidth();
if (width < viewWidth) {
deltaX = (viewWidth - width) / 2 - rect.left;
} else if (rect.left > 0) {
deltaX = -rect.left;
} else if (rect.right < viewWidth) {
deltaX = viewWidth - rect.right;
}
}
postTranslate(deltaX, deltaY);
setImageMatrix(getImageViewMatrix());
}
public ImageViewTouchBase(Context context) {
super(context);
init();
}
public ImageViewTouchBase(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setScaleType(ImageView.ScaleType.MATRIX);
}
protected float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
// Get the scale factor out of the matrix.
protected float getScale(Matrix matrix) {
return getValue(matrix, Matrix.MSCALE_X);
}
public float getScale() {
return getScale(mSuppMatrix);
}
// Setup the base matrix so that the image is centered and scaled properly.
private void getProperBaseMatrix(RotateBitmap bitmap, Matrix matrix) {
float viewWidth = getWidth();
float viewHeight = getHeight();
float w = bitmap.getWidth();
float h = bitmap.getHeight();
matrix.reset();
// We limit up-scaling to 2x otherwise the result may look bad if it's
// a small icon.
float widthScale = Math.min(viewWidth / w, 2.0f);
float heightScale = Math.min(viewHeight / h, 2.0f);
float scale = Math.min(widthScale, heightScale);
matrix.postConcat(bitmap.getRotateMatrix());
matrix.postScale(scale, scale);
matrix.postTranslate((viewWidth - w * scale) / 2F, (viewHeight - h * scale) / 2F);
}
// Combine the base matrix and the supp matrix to make the final matrix.
protected Matrix getImageViewMatrix() {
// The final matrix is computed as the concatentation of the base matrix
// and the supplementary matrix.
mDisplayMatrix.set(mBaseMatrix);
mDisplayMatrix.postConcat(mSuppMatrix);
return mDisplayMatrix;
}
static final float SCALE_RATE = 1.25F;
// Sets the maximum zoom, which is a scale relative to the base matrix. It
// is calculated to show the image at 400% zoom regardless of screen or
// image orientation. If in the future we decode the full 3 megapixel image,
// rather than the current 1024x768, this should be changed down to 200%.
protected float maxZoom() {
if (mBitmapDisplayed.getBitmap() == null) {
return 1F;
}
float fw = (float) mBitmapDisplayed.getWidth() / (float) mThisWidth;
float fh = (float) mBitmapDisplayed.getHeight() / (float) mThisHeight;
float max = Math.max(fw, fh) * 4;
max = (max<1.0f)?1.0f:max;
return max;
}
protected void zoomTo(float scale, float centerX, float centerY) {
if (scale > mMaxZoom) {
scale = mMaxZoom;
}
float oldScale = getScale();
float deltaScale = scale / oldScale;
mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY);
setImageMatrix(getImageViewMatrix());
center(true, true);
}
protected void zoomTo(final float scale, final float centerX, final float centerY, final float durationMs) {
final float incrementPerMs = (scale - getScale()) / durationMs;
final float oldScale = getScale();
final long startTime = System.currentTimeMillis();
mHandler.post(new Runnable() {
@Override
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min(durationMs, now - startTime);
float target = oldScale + (incrementPerMs * currentMs);
zoomTo(target, centerX, centerY);
if (currentMs < durationMs) {
mHandler.post(this);
}
}
});
}
protected void zoomTo(float scale) {
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
zoomTo(scale, cx, cy);
}
protected void zoomIn() {
zoomIn(SCALE_RATE);
}
protected void zoomOut() {
zoomOut(SCALE_RATE);
}
protected void zoomIn(float rate) {
if (getScale() >= mMaxZoom) {
return; // Don't let the user zoom into the molecular level.
}
if (mBitmapDisplayed.getBitmap() == null) {
return;
}
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
mSuppMatrix.postScale(rate, rate, cx, cy);
setImageMatrix(getImageViewMatrix());
}
protected void zoomOut(float rate) {
if (mBitmapDisplayed.getBitmap() == null) {
return;
}
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
// Zoom out to at most 1x.
Matrix tmp = new Matrix(mSuppMatrix);
tmp.postScale(1F / rate, 1F / rate, cx, cy);
if (getScale(tmp) < 1F) {
mSuppMatrix.setScale(1F, 1F, cx, cy);
} else {
mSuppMatrix.postScale(1F / rate, 1F / rate, cx, cy);
}
setImageMatrix(getImageViewMatrix());
center(true, true);
}
protected void postTranslate(float dx, float dy) {
mSuppMatrix.postTranslate(dx, dy);
}
protected void panBy(float dx, float dy) {
postTranslate(dx, dy);
setImageMatrix(getImageViewMatrix());
}
}
从相册中获取图片:
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, FLAG_CHOOSE_IMG);
通过相机获取图片:
String status = Environment.getExternalStorageState();
通过相机获取图片:
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED)) {
try {
localTempImageFileName = "";
localTempImageFileName = String.valueOf((new Date())
.getTime()) + ".png";
File filePath = FILE_PIC_SCREENSHOT;
if (!filePath.exists()) {
filePath.mkdirs();
}
Intent intent1 = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File f = new File(filePath, localTempImageFileName);
// localTempImgDir和localTempImageFileName是自己定义的名字
Uri u = Uri.fromFile(f);
intent1.putExtra(ImageColumns.ORIENTATION, 0);
intent1.putExtra(MediaStore.EXTRA_OUTPUT, u);
startActivityForResult(intent1, FLAG_CHOOSE_PHONE);
} catch (ActivityNotFoundException e) {
//
}
}
在Activity回调中:对不同来源的图片进行处理,先交给裁剪工具,裁剪完后再将图片拿来使用
if (requestCode == FLAG_CHOOSE_IMG && resultCode == RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
if (!TextUtils.isEmpty(uri.getAuthority())) {
Cursor cursor = getContentResolver().query(uri,
new String[] { MediaColumns.DATA }, null, null,
null);
if (null == cursor) {
return;
}
cursor.moveToFirst();
String path = cursor.getString(cursor
.getColumnIndex(MediaColumns.DATA));
cursor.close();
cursor.close();
Intent intent = new Intent(this, CropImageActivity.class);
intent.putExtra("path", path);
startActivityForResult(intent, FLAG_MODIFY_FINISH);
} else {
Intent intent = new Intent(this, CropImageActivity.class);
intent.putExtra("path", uri.getPath());
startActivityForResult(intent, FLAG_MODIFY_FINISH);
}
}
} else if (requestCode == FLAG_CHOOSE_PHONE && resultCode == RESULT_OK) {
File f = new File(FILE_PIC_SCREENSHOT, localTempImageFileName);
Intent intent = new Intent(this, CropImageActivity.class);
intent.putExtra("path", f.getAbsolutePath());
startActivityForResult(intent, FLAG_MODIFY_FINISH);
} else if (requestCode == FLAG_MODIFY_FINISH && resultCode == RESULT_OK) {
if (data != null) {
final String path = data.getStringExtra("path");
Bitmap bm = BitmapFactory.decodeFile(path);
// 裁剪成正方形图片
mIconBitmap = ResizeImage.resizeBitmapWithRadio(bm, 1, 1);
mChild_Icon.setImageBitmap(mIconBitmap);
uploadIconBitmap();
}
}
备注:private static final int FLAG_CHOOSE_IMG = 5;
private static final int FLAG_CHOOSE_PHONE = 6;
private static final int FLAG_MODIFY_FINISH = 7;
public static final String IMAGE_PATH = "My_weixin";
public static final File FILE_SDCARD = Environment
.getExternalStorageDirectory();
public static final File FILE_LOCAL = new File(FILE_SDCARD, IMAGE_PATH);
public static final File FILE_PIC_SCREENSHOT = new File(FILE_LOCAL,
"images/screenshots");
private static String localTempImageFileName = "";