package com.kaixin.android.ui.base;
import java.util.concurrent.CountDownLatch;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
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.Handler;
import com.kaixin.android.activity.ImageFilterCropActivity;
/**
* 裁剪处理
*
*/
public class CropImage {
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("请稍等...", new Runnable() {
public void run() {
final CountDownLatch latch = new CountDownLatch(1);
mHandler.post(new Runnable() {
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("请稍等...", new Runnable() {
public void run() {
final CountDownLatch latch = new CountDownLatch(1);
final Bitmap b = mBitmap;
mHandler.post(new Runnable() {
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 = r.width();// dr.width(); // modify by yc
int height = r.height();// dr.height();
Bitmap croppedImage = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
{
Canvas canvas = new Canvas(croppedImage);
Rect dstRect = new Rect(0, 0, width, height);
canvas.drawBitmap(bm, r, dstRect, null);
}
return croppedImage;
}
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.
@SuppressWarnings("unused")
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;
}
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() {
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;
@SuppressWarnings("unused")
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();
}
public void run() {
final CountDownLatch latch = new CountDownLatch(1);
mHandler.post(new Runnable() {
public void run() {
try {
mHandler.sendMessage(mHandler
.obtainMessage(ImageFilterCropActivity.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(ImageFilterCropActivity.REMOVE_PROGRESS));
// mHandler.post(new Runnable()
// {
// public void run()
// {
// if (mProgress != null && mProgress.isShowing())
// {
// mProgress.dismiss();
// mProgress = null;
// }
// }
// });
}
}
}
}