summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/filtershow/imageshow
diff options
context:
space:
mode:
authorRuben Brunk <rubenbrunk@google.com>2013-04-04 17:20:42 -0700
committerRuben Brunk <rubenbrunk@google.com>2013-04-09 15:57:57 -0700
commit1a664450bed2737660057def2d25b0c6b49b3ba8 (patch)
treeff83702fc2dfd6de0608865d6d2a2d7b9e58fb04 /src/com/android/gallery3d/filtershow/imageshow
parentca13834b449c4586292ca9cc1853fd8e65884edd (diff)
downloadandroid_packages_apps_Snap-1a664450bed2737660057def2d25b0c6b49b3ba8.tar.gz
android_packages_apps_Snap-1a664450bed2737660057def2d25b0c6b49b3ba8.tar.bz2
android_packages_apps_Snap-1a664450bed2737660057def2d25b0c6b49b3ba8.zip
Moving crop to a separate activity. Refactoring.
Bug: 8526929 Change-Id: I8acf6d46de069dd84c31afea6b4a7ae8e1c2fcce
Diffstat (limited to 'src/com/android/gallery3d/filtershow/imageshow')
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java340
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/CropMath.java191
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java2
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java4
4 files changed, 4 insertions, 533 deletions
diff --git a/src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java b/src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java
deleted file mode 100644
index e94d1ed9e..000000000
--- a/src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2012 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.imageshow;
-
-import android.graphics.Matrix;
-import android.graphics.RectF;
-
-import java.util.Arrays;
-
-/**
- * Maintains invariant that inner rectangle is constrained to be within the
- * outer, rotated rectangle.
- */
-public class BoundedRect {
- private float rot;
- private RectF outer;
- private RectF inner;
- private float[] innerRotated;
-
- public BoundedRect() {
- rot = 0;
- outer = new RectF();
- inner = new RectF();
- innerRotated = new float[8];
- }
-
- public BoundedRect(float rotation, RectF outerRect, RectF innerRect) {
- rot = rotation;
- outer = new RectF(outerRect);
- inner = new RectF(innerRect);
- innerRotated = CropMath.getCornersFromRect(inner);
- rotateInner();
- if (!isConstrained())
- reconstrain();
- }
-
- /**
- * Sets inner, and re-constrains it to fit within the rotated bounding rect.
- */
- public void setInner(RectF newInner) {
- if (inner.equals(newInner))
- return;
- inner = newInner;
- innerRotated = CropMath.getCornersFromRect(inner);
- rotateInner();
- if (!isConstrained())
- reconstrain();
- }
-
- /**
- * Sets rotation, and re-constrains inner to fit within the rotated bounding rect.
- */
- public void setRotation(float rotation) {
- if (rotation == rot)
- return;
- rot = rotation;
- innerRotated = CropMath.getCornersFromRect(inner);
- rotateInner();
- if (!isConstrained())
- reconstrain();
- }
-
- public RectF getInner() {
- return new RectF(inner);
- }
-
- /**
- * Tries to move the inner rectangle by (dx, dy). If this would cause it to leave
- * the bounding rectangle, snaps the inner rectangle to the edge of the bounding
- * rectangle.
- */
- public void moveInner(float dx, float dy) {
- Matrix m0 = getInverseRotMatrix();
-
- RectF translatedInner = new RectF(inner);
- translatedInner.offset(dx, dy);
-
- float[] translatedInnerCorners = CropMath.getCornersFromRect(translatedInner);
- float[] outerCorners = CropMath.getCornersFromRect(outer);
-
- m0.mapPoints(translatedInnerCorners);
- float[] correction = {
- 0, 0
- };
-
- // find correction vectors for corners that have moved out of bounds
- for (int i = 0; i < translatedInnerCorners.length; i += 2) {
- float correctedInnerX = translatedInnerCorners[i] + correction[0];
- float correctedInnerY = translatedInnerCorners[i + 1] + correction[1];
- if (!CropMath.inclusiveContains(outer, correctedInnerX, correctedInnerY)) {
- float[] badCorner = {
- correctedInnerX, correctedInnerY
- };
- float[] nearestSide = CropMath.closestSide(badCorner, outerCorners);
- float[] correctionVec =
- GeometryMath.shortestVectorFromPointToLine(badCorner, nearestSide);
- correction[0] += correctionVec[0];
- correction[1] += correctionVec[1];
- }
- }
-
- for (int i = 0; i < translatedInnerCorners.length; i += 2) {
- float correctedInnerX = translatedInnerCorners[i] + correction[0];
- float correctedInnerY = translatedInnerCorners[i + 1] + correction[1];
- if (!CropMath.inclusiveContains(outer, correctedInnerX, correctedInnerY)) {
- float[] correctionVec = {
- correctedInnerX, correctedInnerY
- };
- CropMath.getEdgePoints(outer, correctionVec);
- correctionVec[0] -= correctedInnerX;
- correctionVec[1] -= correctedInnerY;
- correction[0] += correctionVec[0];
- correction[1] += correctionVec[1];
- }
- }
-
- // Set correction
- for (int i = 0; i < translatedInnerCorners.length; i += 2) {
- float correctedInnerX = translatedInnerCorners[i] + correction[0];
- float correctedInnerY = translatedInnerCorners[i + 1] + correction[1];
- // update translated corners with correction vectors
- translatedInnerCorners[i] = correctedInnerX;
- translatedInnerCorners[i + 1] = correctedInnerY;
- }
-
- innerRotated = translatedInnerCorners;
- // reconstrain to update inner
- reconstrain();
- }
-
- /**
- * Attempts to resize the inner rectangle. If this would cause it to leave
- * the bounding rect, clips the inner rectangle to fit.
- */
- public void resizeInner(RectF newInner) {
- Matrix m = getRotMatrix();
- Matrix m0 = getInverseRotMatrix();
-
- float[] outerCorners = CropMath.getCornersFromRect(outer);
- m.mapPoints(outerCorners);
- float[] oldInnerCorners = CropMath.getCornersFromRect(inner);
- float[] newInnerCorners = CropMath.getCornersFromRect(newInner);
- RectF ret = new RectF(newInner);
-
- for (int i = 0; i < newInnerCorners.length; i += 2) {
- float[] c = {
- newInnerCorners[i], newInnerCorners[i + 1]
- };
- float[] c0 = Arrays.copyOf(c, 2);
- m0.mapPoints(c0);
- if (!CropMath.inclusiveContains(outer, c0[0], c0[1])) {
- float[] outerSide = CropMath.closestSide(c, outerCorners);
- float[] pathOfCorner = {
- newInnerCorners[i], newInnerCorners[i + 1],
- oldInnerCorners[i], oldInnerCorners[i + 1]
- };
- float[] p = GeometryMath.lineIntersect(pathOfCorner, outerSide);
- if (p == null) {
- // lines are parallel or not well defined, so don't resize
- p = new float[2];
- p[0] = oldInnerCorners[i];
- p[1] = oldInnerCorners[i + 1];
- }
- // relies on corners being in same order as method
- // getCornersFromRect
- switch (i) {
- case 0:
- case 1:
- ret.left = (p[0] > ret.left) ? p[0] : ret.left;
- ret.top = (p[1] > ret.top) ? p[1] : ret.top;
- break;
- case 2:
- case 3:
- ret.right = (p[0] < ret.right) ? p[0] : ret.right;
- ret.top = (p[1] > ret.top) ? p[1] : ret.top;
- break;
- case 4:
- case 5:
- ret.right = (p[0] < ret.right) ? p[0] : ret.right;
- ret.bottom = (p[1] < ret.bottom) ? p[1] : ret.bottom;
- break;
- case 6:
- case 7:
- ret.left = (p[0] > ret.left) ? p[0] : ret.left;
- ret.bottom = (p[1] < ret.bottom) ? p[1] : ret.bottom;
- break;
- default:
- break;
- }
- }
- }
- float[] retCorners = CropMath.getCornersFromRect(ret);
- m0.mapPoints(retCorners);
- innerRotated = retCorners;
- // reconstrain to update inner
- reconstrain();
- }
-
- /**
- * Attempts to resize the inner rectangle. If this would cause it to leave
- * the bounding rect, clips the inner rectangle to fit while maintaining
- * aspect ratio.
- */
- public void fixedAspectResizeInner(RectF newInner) {
- Matrix m = getRotMatrix();
- Matrix m0 = getInverseRotMatrix();
-
- float aspectW = inner.width();
- float aspectH = inner.height();
- float aspRatio = aspectW / aspectH;
- float[] corners = CropMath.getCornersFromRect(outer);
-
- m.mapPoints(corners);
- float[] oldInnerCorners = CropMath.getCornersFromRect(inner);
- float[] newInnerCorners = CropMath.getCornersFromRect(newInner);
-
- // find fixed corner
- int fixed = -1;
- if (inner.top == newInner.top) {
- if (inner.left == newInner.left)
- fixed = 0; // top left
- else if (inner.right == newInner.right)
- fixed = 2; // top right
- } else if (inner.bottom == newInner.bottom) {
- if (inner.right == newInner.right)
- fixed = 4; // bottom right
- else if (inner.left == newInner.left)
- fixed = 6; // bottom left
- }
- // no fixed corner, return without update
- if (fixed == -1)
- return;
- float widthSoFar = newInner.width();
- int moved = -1;
- for (int i = 0; i < newInnerCorners.length; i += 2) {
- float[] c = {
- newInnerCorners[i], newInnerCorners[i + 1]
- };
- float[] c0 = Arrays.copyOf(c, 2);
- m0.mapPoints(c0);
- if (!CropMath.inclusiveContains(outer, c0[0], c0[1])) {
- moved = i;
- if (moved == fixed)
- continue;
- float[] l2 = CropMath.closestSide(c, corners);
- float[] l1 = {
- newInnerCorners[i], newInnerCorners[i + 1],
- oldInnerCorners[i], oldInnerCorners[i + 1]
- };
- float[] p = GeometryMath.lineIntersect(l1, l2);
- if (p == null) {
- // lines are parallel or not well defined, so set to old
- // corner
- p = new float[2];
- p[0] = oldInnerCorners[i];
- p[1] = oldInnerCorners[i + 1];
- }
- // relies on corners being in same order as method
- // getCornersFromRect
- float fixed_x = oldInnerCorners[fixed];
- float fixed_y = oldInnerCorners[fixed + 1];
- float newWidth = Math.abs(fixed_x - p[0]);
- float newHeight = Math.abs(fixed_y - p[1]);
- newWidth = Math.max(newWidth, aspRatio * newHeight);
- if (newWidth < widthSoFar)
- widthSoFar = newWidth;
- }
- }
-
- float heightSoFar = widthSoFar / aspRatio;
- RectF ret = new RectF(inner);
- if (fixed == 0) {
- ret.right = ret.left + widthSoFar;
- ret.bottom = ret.top + heightSoFar;
- } else if (fixed == 2) {
- ret.left = ret.right - widthSoFar;
- ret.bottom = ret.top + heightSoFar;
- } else if (fixed == 4) {
- ret.left = ret.right - widthSoFar;
- ret.top = ret.bottom - heightSoFar;
- } else if (fixed == 6) {
- ret.right = ret.left + widthSoFar;
- ret.top = ret.bottom - heightSoFar;
- }
- float[] retCorners = CropMath.getCornersFromRect(ret);
- m0.mapPoints(retCorners);
- innerRotated = retCorners;
- // reconstrain to update inner
- reconstrain();
- }
-
- // internal methods
-
- private boolean isConstrained() {
- for (int i = 0; i < 8; i += 2) {
- if (!CropMath.inclusiveContains(outer, innerRotated[i], innerRotated[i + 1]))
- return false;
- }
- return true;
- }
-
- private void reconstrain() {
- // innerRotated has been changed to have incorrect values
- CropMath.getEdgePoints(outer, innerRotated);
- Matrix m = getRotMatrix();
- float[] unrotated = Arrays.copyOf(innerRotated, 8);
- m.mapPoints(unrotated);
- inner = CropMath.trapToRect(unrotated);
- }
-
- private void rotateInner() {
- Matrix m = getInverseRotMatrix();
- m.mapPoints(innerRotated);
- }
-
- private Matrix getRotMatrix() {
- Matrix m = new Matrix();
- m.setRotate(rot, outer.centerX(), outer.centerY());
- return m;
- }
-
- private Matrix getInverseRotMatrix() {
- Matrix m = new Matrix();
- m.setRotate(-rot, outer.centerX(), outer.centerY());
- return m;
- }
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/CropMath.java b/src/com/android/gallery3d/filtershow/imageshow/CropMath.java
deleted file mode 100644
index 9037ca043..000000000
--- a/src/com/android/gallery3d/filtershow/imageshow/CropMath.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2012 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.imageshow;
-
-import android.graphics.Matrix;
-import android.graphics.RectF;
-
-import java.util.Arrays;
-
-public class CropMath {
-
- /**
- * Gets a float array of the 2D coordinates representing a rectangles
- * corners.
- * The order of the corners in the float array is:
- * 0------->1
- * ^ |
- * | v
- * 3<-------2
- *
- * @param r the rectangle to get the corners of
- * @return the float array of corners (8 floats)
- */
-
- public static float[] getCornersFromRect(RectF r) {
- float[] corners = {
- r.left, r.top,
- r.right, r.top,
- r.right, r.bottom,
- r.left, r.bottom
- };
- return corners;
- }
-
- /**
- * Returns true iff point (x, y) is within or on the rectangle's bounds.
- * RectF's "contains" function treats points on the bottom and right bound
- * as not being contained.
- *
- * @param r the rectangle
- * @param x the x value of the point
- * @param y the y value of the point
- * @return
- */
- public static boolean inclusiveContains(RectF r, float x, float y) {
- return !(x > r.right || x < r.left || y > r.bottom || y < r.top);
- }
-
- /**
- * Takes an array of 2D coordinates representing corners and returns the
- * smallest rectangle containing those coordinates.
- *
- * @param array array of 2D coordinates
- * @return smallest rectangle containing coordinates
- */
- public static RectF trapToRect(float[] array) {
- RectF r = new RectF(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY,
- Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
- for (int i = 1; i < array.length; i += 2) {
- float x = array[i - 1];
- float y = array[i];
- r.left = (x < r.left) ? x : r.left;
- r.top = (y < r.top) ? y : r.top;
- r.right = (x > r.right) ? x : r.right;
- r.bottom = (y > r.bottom) ? y : r.bottom;
- }
- r.sort();
- return r;
- }
-
- /**
- * If edge point [x, y] in array [x0, y0, x1, y1, ...] is outside of the
- * image bound rectangle, clamps it to the edge of the rectangle.
- *
- * @param imageBound the rectangle to clamp edge points to.
- * @param array an array of points to clamp to the rectangle, gets set to
- * the clamped values.
- */
- public static void getEdgePoints(RectF imageBound, float[] array) {
- if (array.length < 2)
- return;
- for (int x = 0; x < array.length; x += 2) {
- array[x] = GeometryMath.clamp(array[x], imageBound.left, imageBound.right);
- array[x + 1] = GeometryMath.clamp(array[x + 1], imageBound.top, imageBound.bottom);
- }
- }
-
- /**
- * Takes a point and the corners of a rectangle and returns the two corners
- * representing the side of the rectangle closest to the point.
- *
- * @param point the point which is being checked
- * @param corners the corners of the rectangle
- * @return two corners representing the side of the rectangle
- */
- public static float[] closestSide(float[] point, float[] corners) {
- int len = corners.length;
- float oldMag = Float.POSITIVE_INFINITY;
- float[] bestLine = null;
- for (int i = 0; i < len; i += 2) {
- float[] line = {
- corners[i], corners[(i + 1) % len],
- corners[(i + 2) % len], corners[(i + 3) % len]
- };
- float mag = GeometryMath.vectorLength(
- GeometryMath.shortestVectorFromPointToLine(point, line));
- if (mag < oldMag) {
- oldMag = mag;
- bestLine = line;
- }
- }
- return bestLine;
- }
-
- /**
- * Checks if a given point is within a rotated rectangle.
- *
- * @param point 2D point to check
- * @param bound rectangle to rotate
- * @param rot angle of rotation about rectangle center
- * @return true if point is within rotated rectangle
- */
- public static boolean pointInRotatedRect(float[] point, RectF bound, float rot) {
- Matrix m = new Matrix();
- float[] p = Arrays.copyOf(point, 2);
- m.setRotate(rot, bound.centerX(), bound.centerY());
- Matrix m0 = new Matrix();
- if (!m.invert(m0))
- return false;
- m0.mapPoints(p);
- return inclusiveContains(bound, p[0], p[1]);
- }
-
- /**
- * Checks if a given point is within a rotated rectangle.
- *
- * @param point 2D point to check
- * @param rotatedRect corners of a rotated rectangle
- * @param center center of the rotated rectangle
- * @return true if point is within rotated rectangle
- */
- public static boolean pointInRotatedRect(float[] point, float[] rotatedRect, float[] center) {
- RectF unrotated = new RectF();
- float angle = getUnrotated(rotatedRect, center, unrotated);
- return pointInRotatedRect(point, unrotated, angle);
- }
-
- /**
- * Resizes rectangle to have a certain aspect ratio (center remains
- * stationary).
- *
- * @param r rectangle to resize
- * @param w new width aspect
- * @param h new height aspect
- */
- public static void fixAspectRatio(RectF r, float w, float h) {
- float scale = Math.min(r.width() / w, r.height() / h);
- float centX = r.centerX();
- float centY = r.centerY();
- float hw = scale * w / 2;
- float hh = scale * h / 2;
- r.set(centX - hw, centY - hh, centX + hw, centY + hh);
- }
-
- private static float getUnrotated(float[] rotatedRect, float[] center, RectF unrotated) {
- float dy = rotatedRect[1] - rotatedRect[3];
- float dx = rotatedRect[0] - rotatedRect[2];
- float angle = (float) (Math.atan(dy / dx) * 180 / Math.PI);
- Matrix m = new Matrix();
- m.setRotate(-angle, center[0], center[1]);
- float[] unrotatedRect = new float[rotatedRect.length];
- m.mapPoints(unrotatedRect, rotatedRect);
- unrotated.set(trapToRect(unrotatedRect));
- return angle;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
index ad2152ab1..898fdf021 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
@@ -21,8 +21,8 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
-import com.android.gallery3d.filtershow.CropExtras;
import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.crop.CropExtras;
import com.android.gallery3d.filtershow.editors.EditorCrop;
import com.android.gallery3d.filtershow.editors.EditorFlip;
import com.android.gallery3d.filtershow.editors.EditorRotate;
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
index 2ea6f6a42..6d62bbd1d 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
@@ -33,7 +33,9 @@ import android.widget.LinearLayout;
import android.widget.PopupMenu;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.CropExtras;
+import com.android.gallery3d.filtershow.crop.BoundedRect;
+import com.android.gallery3d.filtershow.crop.CropExtras;
+import com.android.gallery3d.filtershow.crop.CropMath;
import com.android.gallery3d.filtershow.editors.EditorCrop;
import com.android.gallery3d.filtershow.ui.FramedTextButton;