summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/filtershow/crop/CropView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/filtershow/crop/CropView.java')
-rw-r--r--src/com/android/gallery3d/filtershow/crop/CropView.java278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/filtershow/crop/CropView.java b/src/com/android/gallery3d/filtershow/crop/CropView.java
new file mode 100644
index 000000000..561f7ae7f
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/crop/CropView.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.crop;
+
+import android.content.Context;
+import android.content.res.Resources;
+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.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.gallery3d.R;
+
+public class CropView extends View {
+ private static final String LOGTAG = "CropView";
+
+ Bitmap mImage = null;
+ CropObject mCropObj = null;
+ private final Drawable mCropIndicator;
+ private final int mIndicatorSize;
+
+ private float mPrevX = 0;
+ private float mPrevY = 0;
+
+ private int mMinSideSize = 45;
+ private int mTouchTolerance = 20;
+ private boolean mMovingBlock = false;
+
+ private Matrix mDisplayMatrix = null;
+ private Matrix mDisplayMatrixInverse = null;
+
+ private enum Mode {
+ NONE, MOVE
+ }
+
+ private Mode mState = Mode.NONE;
+
+ public CropView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ Resources resources = context.getResources();
+ mCropIndicator = resources.getDrawable(R.drawable.camera_crop);
+ mIndicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
+ }
+
+ // For unchanging parameters
+ public void setup(Bitmap image, int minSideSize, int touchTolerance) {
+ mImage = image;
+ mMinSideSize = minSideSize;
+ mTouchTolerance = touchTolerance;
+ reset();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (mImage == null) {
+ return;
+ }
+ int displayWidth = getWidth();
+ int displayHeight = getHeight();
+ Rect imageBoundsOriginal = new Rect(0, 0, mImage.getWidth(), mImage.getHeight());
+ Rect displayBoundsOriginal = new Rect(0, 0, displayWidth, displayHeight);
+ if (mCropObj == null) {
+ reset();
+ mCropObj = new CropObject(imageBoundsOriginal, imageBoundsOriginal, 0);
+ }
+
+ RectF imageBounds = mCropObj.getInnerBounds();
+ RectF displayBounds = mCropObj.getOuterBounds();
+
+ // If display matrix doesn't exist, create it and its dependencies
+ if (mDisplayMatrix == null || mDisplayMatrixInverse == null) {
+ mDisplayMatrix = getBitmapToDisplayMatrix(displayBounds, new RectF(
+ displayBoundsOriginal));
+ mDisplayMatrixInverse = new Matrix();
+ mDisplayMatrixInverse.reset();
+ if (!mDisplayMatrix.invert(mDisplayMatrixInverse)) {
+ Log.w(LOGTAG, "could not invert display matrix");
+ }
+ // Scale min side and tolerance by display matrix scale factor
+ mCropObj.setMinInnerSideSize(mDisplayMatrixInverse.mapRadius(mMinSideSize));
+ mCropObj.setTouchTolerance(mDisplayMatrixInverse.mapRadius(mTouchTolerance));
+ }
+ canvas.drawBitmap(mImage, mDisplayMatrix, new Paint());
+
+ if (mDisplayMatrix.mapRect(imageBounds)) {
+ drawCropRect(canvas, imageBounds);
+ drawRuleOfThird(canvas, imageBounds);
+ drawIndicators(canvas, mCropIndicator, mIndicatorSize, imageBounds,
+ mCropObj.isFixedAspect(), mCropObj.getSelectState());
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ float x = event.getX();
+ float y = event.getY();
+ if (mDisplayMatrix == null || mDisplayMatrixInverse == null) {
+ return true;
+ }
+ float[] touchPoint = {
+ x, y
+ };
+ mDisplayMatrixInverse.mapPoints(touchPoint);
+ x = touchPoint[0];
+ y = touchPoint[1];
+ switch (event.getActionMasked()) {
+ case (MotionEvent.ACTION_DOWN):
+ if (mState == Mode.NONE) {
+ if (!mCropObj.selectEdge(x, y)) {
+ mMovingBlock = mCropObj.selectEdge(CropObject.MOVE_BLOCK);
+ }
+ mPrevX = x;
+ mPrevY = y;
+ mState = Mode.MOVE;
+ } else {
+ reset();
+ }
+ break;
+ case (MotionEvent.ACTION_UP):
+ if (mState == Mode.MOVE) {
+ mCropObj.selectEdge(CropObject.MOVE_NONE);
+ mMovingBlock = false;
+ mPrevX = x;
+ mPrevY = y;
+ mState = Mode.NONE;
+ } else {
+ reset();
+ }
+ break;
+ case (MotionEvent.ACTION_MOVE):
+ if (mState == Mode.MOVE) {
+ float dx = x - mPrevX;
+ float dy = y - mPrevY;
+ mCropObj.moveCurrentSelection(dx, dy);
+ mPrevX = x;
+ mPrevY = y;
+ } else {
+ reset();
+ }
+ break;
+ default:
+ reset();
+ break;
+ }
+ invalidate();
+ return true;
+ }
+
+ public void reset() {
+ Log.w(LOGTAG, "reset called");
+ mState = Mode.NONE;
+ mCropObj = null;
+ mDisplayMatrix = null;
+ mDisplayMatrixInverse = null;
+ mMovingBlock = false;
+ invalidate();
+ }
+
+ public boolean getCropBounds(RectF out_crop, RectF in_newContaining) {
+ Matrix m = new Matrix();
+ RectF inner = mCropObj.getInnerBounds();
+ RectF outer = mCropObj.getOuterBounds();
+ if (!m.setRectToRect(outer, in_newContaining, Matrix.ScaleToFit.FILL)) {
+ Log.w(LOGTAG, "failed to make transform matrix");
+ return false;
+ }
+ if (!m.mapRect(inner)) {
+ Log.w(LOGTAG, "failed to transform crop bounds");
+ return false;
+ }
+ out_crop.set(inner);
+ return true;
+ }
+
+ // Helper methods
+
+ private static void drawRuleOfThird(Canvas canvas, RectF bounds) {
+ Paint p = new Paint();
+ p.setStyle(Paint.Style.STROKE);
+ p.setColor(Color.argb(128, 255, 255, 255));
+ p.setStrokeWidth(2);
+ float stepX = bounds.width() / 3.0f;
+ float stepY = bounds.height() / 3.0f;
+ float x = bounds.left + stepX;
+ float y = bounds.top + stepY;
+ for (int i = 0; i < 2; i++) {
+ canvas.drawLine(x, bounds.top, x, bounds.bottom, p);
+ x += stepX;
+ }
+ for (int j = 0; j < 2; j++) {
+ canvas.drawLine(bounds.left, y, bounds.right, y, p);
+ y += stepY;
+ }
+ }
+
+ private static void drawCropRect(Canvas canvas, RectF bounds) {
+ Paint p = new Paint();
+ p.setStyle(Paint.Style.STROKE);
+ p.setColor(Color.WHITE);
+ p.setStrokeWidth(3);
+ canvas.drawRect(bounds, p);
+ }
+
+ private static void drawIndicator(Canvas canvas, Drawable indicator, int indicatorSize,
+ float centerX, float centerY) {
+ int left = (int) centerX - indicatorSize / 2;
+ int top = (int) centerY - indicatorSize / 2;
+ indicator.setBounds(left, top, left + indicatorSize, top + indicatorSize);
+ indicator.draw(canvas);
+ }
+
+ private static void drawIndicators(Canvas canvas, Drawable cropIndicator, int indicatorSize,
+ RectF bounds, boolean fixedAspect, int selection) {
+ boolean notMoving = (selection == CropObject.MOVE_NONE);
+ if (fixedAspect) {
+ if ((selection == CropObject.TOP_LEFT) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.left, bounds.top);
+ }
+ if ((selection == CropObject.TOP_RIGHT) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.right, bounds.top);
+ }
+ if ((selection == CropObject.BOTTOM_LEFT) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.left, bounds.bottom);
+ }
+ if ((selection == CropObject.BOTTOM_RIGHT) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.right, bounds.bottom);
+ }
+ } else {
+ if (((selection & CropObject.MOVE_TOP) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.centerX(), bounds.top);
+ }
+ if (((selection & CropObject.MOVE_BOTTOM) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.centerX(), bounds.bottom);
+ }
+ if (((selection & CropObject.MOVE_LEFT) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.left, bounds.centerY());
+ }
+ if (((selection & CropObject.MOVE_RIGHT) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, indicatorSize, bounds.right, bounds.centerY());
+ }
+ }
+ }
+
+ private static Matrix getBitmapToDisplayMatrix(RectF imageBounds, RectF displayBounds) {
+ Matrix m = new Matrix();
+ setBitmapToDisplayMatrix(m, imageBounds, displayBounds);
+ return m;
+ }
+
+ private static boolean setBitmapToDisplayMatrix(Matrix m, RectF imageBounds,
+ RectF displayBounds) {
+ m.reset();
+ return m.setRectToRect(imageBounds, displayBounds, Matrix.ScaleToFit.CENTER);
+ }
+
+}