package com.ijoomer.customviews; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.media.FaceDetector; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.ViewTreeObserver; import android.widget.ImageView; import com.androidquery.AQuery; import com.androidquery.callback.AjaxCallback; import com.androidquery.callback.AjaxStatus; import com.ijoomer.custom.interfaces.PhotoTagListener; import com.ijoomer.src.R; import java.util.ArrayList; import java.util.HashMap; /** * This Class Contains All Method Related To PhotoTagView. * * @author tasol * */ @SuppressLint("DefaultLocale") public class PhotoTagView extends ImageView { private ArrayList<HashMap<String, String>> tagedUserList; private GestureDetector gestureDetector; PhotoTagListener photoTagListener; private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); Paint textPaint; Paint textBackGroundPaint; Bitmap tagLabelBitmap; Bitmap cancelTag; AQuery aQuery; private static final int MAX_FACES = 10; private RectF[] facesRect; private RectF cancelRect; private RectF[] tagedUserRect; private RectF[] tagedUserLabelRect; private int[] mPX = null; private int[] mPY = null; RectF tagRect; String tagImageUrl; int tagLabelResource = 0; int originalImageWidth; int originalImageHeight; float[] pts; float x, y; float width; float height; boolean isCancel = true; int ih; int iw; int iH; int iW; @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); originalImageWidth = bm.getWidth(); originalImageHeight = bm.getHeight(); ih = getMeasuredHeight();// height of imageView iw = getMeasuredWidth();// width of imageView iH = getDrawable().getIntrinsicHeight();// original height of underlying iW = getDrawable().getIntrinsicWidth(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawCanvas(canvas); } @Override public boolean onTouchEvent(MotionEvent event) { if (!isCancel) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (cancelRect.contains(event.getX(), event.getY())) { isCancel = true; if (photoTagListener != null) { photoTagListener.onCancel(); } invalidate(); return true; } } x = event.getX(); y = event.getY(); invalidate(); return true; } else { gestureDetector.onTouchEvent(event); } return true; } public PhotoTagView(Context c) { super(c); init(); } public PhotoTagView(Context c, AttributeSet attrs) { super(c, attrs); setDrawingCacheEnabled(true); init(); } private void init() { ViewTreeObserver vto = getViewTreeObserver(); vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { if (ih <= 0 && iw <= 0) { try { ih = getMeasuredHeight();// height of imageView iw = getMeasuredWidth();// width of imageView iH = getDrawable().getIntrinsicHeight();// original // height // of underlying // image iW = getDrawable().getIntrinsicWidth(); if (ih / iH <= iw / iW) iw = iW * ih / iH;// rescaled width of image within else ih = iH * iw / iW; if (iw > 0 && ih > 0) { setFace(iw, ih); } } catch (Exception e) { } } return true; } }); cancelRect = new RectF(); cancelTag = BitmapFactory.decodeResource(getResources(), R.drawable.com_facebook_close); gestureDetector = new GestureDetector(getContext(), new SingleTapConfirm()); aQuery = new AQuery(this); width = convertSizeToDeviceDependent(50); height = convertSizeToDeviceDependent(50); textBackGroundPaint = new Paint(); textBackGroundPaint.setColor(Color.BLACK); textBackGroundPaint.setStyle(Paint.Style.FILL); textPaint = new Paint(); textPaint.setColor(Color.WHITE); textPaint.setTextSize(convertSizeToDeviceDependent(12)); tagRect = new RectF(); } /** * This method used to get taged user list. * * @return represented {@link HashMap} list */ public ArrayList<HashMap<String, String>> getTagedUserList() { return tagedUserList; } /** * This method used to set taged user list. * * @param tagedUserList * represented user list */ public void setTagedUserList(ArrayList<HashMap<String, String>> tagedUserList) { this.tagedUserList = tagedUserList; if (tagedUserList != null && tagedUserList.size() > 0) { tagedUserRect = new RectF[tagedUserList.size()]; tagedUserLabelRect = new RectF[tagedUserList.size()]; if (photoTagListener != null) { photoTagListener.showTagOptions(isCancel); } } else { if (tagedUserRect != null && tagedUserRect.length > 0) { if (photoTagListener != null) { photoTagListener.showTagOptions(isCancel); } tagedUserLabelRect = null; tagedUserRect = null; } } drawDetectedFace(); photoTagListener.showTagOptions(isCancel); } /** * This method used to set tag label resource id. * * @param tagLabelResource * represented resource id */ public void setTagLabelResource(int tagLabelResource) { this.tagLabelResource = tagLabelResource; tagLabelBitmap = BitmapFactory.decodeResource(getResources(), tagLabelResource); } /** * This method used to get tag listener. * * @return represented {@link PhotoTagListener} */ public PhotoTagListener getPhotoTagListener() { return photoTagListener; } /** * This method used to set tag listener. * * @param photoTagListener * represented listener */ public void setPhotoTagListener(PhotoTagListener photoTagListener) { this.photoTagListener = photoTagListener; } /** * This method used to set add tag. */ public void setAddTag() { isCancel = false; x = getWidth() / 2.0f; y = getHeight() / 2.0f; invalidate(); } /** * This method used to convert size to device dependent. * * @param value * represented size * @return represented {@link Integer} */ public int convertSizeToDeviceDependent(int value) { DisplayMetrics dm = new DisplayMetrics(); ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm); return ((dm.densityDpi * value) / 160); } /** * This method used to add new tag. */ public void addNewTag() { if (photoTagListener != null) { if (getTagedUserList() != null) { boolean isValidTagPosition = true; int size = getTagedUserList().size(); for (int i = 0; i < size; i++) { if (tagedUserRect[i].intersect(getDeviceRectFromData(getTaggedPositionData(tagRect)))) { isValidTagPosition = false; break; } } if (isValidTagPosition) { photoTagListener.onAddNewTag(getTaggedPositionData(tagRect)); } else { photoTagListener.onTagAreaConflict(); } } else { photoTagListener.onAddNewTag(getTaggedPositionData(tagRect)); } } } /** * This method used to set tag image url. * * @param imageUrl * represented url */ public void setTagImageUrl(String imageUrl) { this.tagImageUrl = imageUrl; aQuery.ajax(imageUrl, Bitmap.class, 0, new AjaxCallback<Bitmap>() { @Override public void callback(String url, Bitmap object, AjaxStatus status) { super.callback(url, object, status); originalImageWidth = object.getWidth(); originalImageHeight = object.getHeight(); setImageBitmap(object); } }); } /** * This method used to draw canvas * * @param canvas * represented canvas */ private void drawCanvas(Canvas canvas) { try { if (getTagedUserList() != null) { int size = getTagedUserList().size(); for (int i = 0; i < size; i++) { tagedUserRect[i] = getDeviceRectFromData(getTagedUserList().get(i).get("position")); Rect textBound = new Rect(); textPaint.getTextBounds(getTagedUserList().get(i).get("user_name"), 0, getTagedUserList().get(i).get("user_name").length(), textBound); tagedUserLabelRect[i] = new RectF(new RectF(tagedUserRect[i].left, tagedUserRect[i].bottom - convertSizeToDeviceDependent(15), tagedUserRect[i].left + textBound.width() + convertSizeToDeviceDependent(9), (tagedUserRect[i].bottom - convertSizeToDeviceDependent(20)) + textBound.height() + convertSizeToDeviceDependent(15))); Rect src = new Rect(); src.set(0, 0, tagLabelBitmap.getWidth(), tagLabelBitmap.getHeight()); canvas.drawBitmap(tagLabelBitmap, src, tagedUserLabelRect[i], null); canvas.drawText(getTagedUserList().get(i).get("user_name"), tagedUserRect[i].left + convertSizeToDeviceDependent(3), tagedUserRect[i].bottom, textPaint); } } if (!isCancel) { x = (x - width); y = (y - height); x = x <= 0 ? 0.0f : x; x = x >= getWidth() ? getWidth() : x; y = y <= 0 ? 0.0f : y; y = y >= getHeight() ? getHeight() : y; if (x + width > getWidth()) { x = x - Math.abs((getWidth() - (x + width))); } if (y + height > getHeight()) { y = y - Math.abs((getHeight() - (y + height))); } mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setColor(Color.RED); mPaint.setStrokeWidth(convertSizeToDeviceDependent(3)); mPaint.setPathEffect(null); canvas.drawRect(x, y, x + width, y + height, mPaint); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setColor(Color.WHITE); mPaint.setStrokeWidth(convertSizeToDeviceDependent(3)); mPaint.setPathEffect(new DashPathEffect(new float[] { 5, 5 }, 5)); canvas.drawRect(x, y, x + width, y + height, mPaint); tagRect.left = x; tagRect.top = y; tagRect.right = x + width; tagRect.bottom = y + height; cancelRect.left = tagRect.left + cancelTag.getWidth() + convertSizeToDeviceDependent(5); cancelRect.top = tagRect.top - cancelTag.getHeight() + convertSizeToDeviceDependent(10); cancelRect.right = cancelRect.left + cancelTag.getWidth(); cancelRect.bottom = cancelRect.top + cancelTag.getHeight(); canvas.drawBitmap(cancelTag, cancelRect.left, cancelRect.top, null); } } catch (Exception e) { e.printStackTrace(); } } /** * This method used to get device Rect from data. * * @param pointData * represented data * @return represented {@link RectF} */ private RectF getDeviceRectFromData(String pointData) { float width, height, left, top; width = height = left = top = 0; String strPos[] = pointData.split(","); width = Float.parseFloat(strPos[2]) * originalImageWidth; height = Float.parseFloat(strPos[3]) * originalImageHeight; top = (Float.parseFloat(strPos[0]) * originalImageHeight) - (height / 2); left = (Float.parseFloat(strPos[1]) * originalImageWidth) - (width / 2); width = (getWidth() * width) / originalImageWidth; height = (getHeight() * height) / originalImageHeight; left = (getWidth() * left) / originalImageWidth; top = (getHeight() * top) / originalImageHeight; RectF rectF = new RectF(left, top, (left + width), (top + height)); return rectF; } /** * This method used to get tagged position data. * * @param tagRect * represented tagged RectF * @return represented {@link String} */ public String getTaggedPositionData(RectF tagRect) { // 'top' : (photoTagSize.y1 + (photoTagSize.height / 2)) / // photo.height(), // 'left' : (photoTagSize.x1 + (photoTagSize.width / 2)) / // photo.width(), // 'width' : photoTagSize.width / photo.width(), // 'height' : photoTagSize.height / photo.height() float width, height, left, top; width = height = left = top = 0; width = (tagRect.width() / getWidth()); height = (tagRect.height()) / getHeight(); top = (tagRect.top + (tagRect.height() / 2)) / getHeight(); left = (tagRect.left + (tagRect.width() / 2)) / getWidth(); return String.format(String.format("%.2f,%.2f,%.2f,%.2f", top, left, width, height)); } /** * Inner class * * @author tasol * */ private class SingleTapConfirm extends SimpleOnGestureListener { @Override public boolean onSingleTapConfirmed(MotionEvent event) { try { if (getTagedUserList() != null) { int i; int size = getTagedUserList().size(); for (i = 0; i < size; i++) { if (tagedUserLabelRect[i].contains((int) event.getX(), (int) event.getY())) { break; } } if (photoTagListener != null && (i != size)) { photoTagListener.onTagedItemClicked(i, getTagedUserList().get(i)); return false; } } } catch (Exception e) { } return true; } } private void setFace(final int w, final int h) { new AsyncTask<Void, Void, Void>() { int[] fpx = null; int[] fpy = null; int count = 0; Bitmap faceBitmap = getDrawingCache(); protected void onPreExecute() { faceBitmap = faceBitmap.copy(Config.RGB_565, true); }; @Override protected Void doInBackground(Void... params) { FaceDetector fd; FaceDetector.Face[] faces = new FaceDetector.Face[MAX_FACES]; PointF midpoint = new PointF(); try { fd = new FaceDetector(w, h, MAX_FACES); count = fd.findFaces(faceBitmap, faces); faceBitmap.recycle(); faceBitmap = null; } catch (Exception e) { faceBitmap.recycle(); faceBitmap = null; return null; } // check if we detect any faces if (count > 0) { facesRect = new RectF[count]; fpx = new int[count]; fpy = new int[count]; for (int i = 0; i < count; i++) { try { faces[i].getMidPoint(midpoint); fpx[i] = (int) midpoint.x; fpy[i] = (int) midpoint.y; } catch (Exception e) { } } } return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); setDisplayPoints(fpx, fpy, count); } }.execute(); } private void setDisplayPoints(int[] xx, int[] yy, int total) { mPX = null; mPY = null; if (xx != null && yy != null && total > 0) { mPX = new int[total]; mPY = new int[total]; for (int i = 0; i < total; i++) { mPX[i] = xx[i] + 20; mPY[i] = yy[i] + 40; } for (int i = 0; i < mPX.length; i++) { facesRect[i] = new RectF(mPX[i], mPY[i], mPX[i] + 50, mPY[i] + 50); } drawDetectedFace(); } } private void drawDetectedFace() { try { isCancel = true; if (tagedUserRect != null && tagedUserRect.length > 0) { int size = facesRect.length; for (int j = 0; j < size; j++) { boolean tagExists = false; int tagedUserRectSize = tagedUserRect.length; for (int k = 0; k < tagedUserRectSize; k++) { if (tagedUserRect[k].intersect(facesRect[j]) || tagedUserRect[k].contains(facesRect[j])) { tagExists = true; break; } } if (!tagExists) { x = facesRect[j].left; y = facesRect[j].top; isCancel = false; } } } else { if (facesRect != null && facesRect.length > 0) { isCancel = false; x = facesRect[0].left; y = facesRect[0].top; } } invalidate(); photoTagListener.showTagOptions(isCancel); } catch (Exception e) { } invalidate(); } }