summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/gallery3d/filtershow/EditorPlaceHolder.java33
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java24
-rw-r--r--src/com/android/gallery3d/filtershow/crop/BoundedRect.java8
-rw-r--r--src/com/android/gallery3d/filtershow/crop/CropMath.java10
-rw-r--r--src/com/android/gallery3d/filtershow/crop/CropObject.java7
-rw-r--r--src/com/android/gallery3d/filtershow/crop/CropView.java19
-rw-r--r--src/com/android/gallery3d/filtershow/editors/Editor.java45
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorCrop.java106
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorMirror.java (renamed from src/com/android/gallery3d/filtershow/editors/EditorFlip.java)49
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorPanel.java17
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorRotate.java35
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorStraighten.java34
-rw-r--r--src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java24
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java71
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java33
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java27
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java16
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilter.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java117
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java89
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryListener.java21
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java143
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java416
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java490
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java854
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java6
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java160
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java527
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageMirror.java78
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java6
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java66
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java54
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java235
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/MasterImage.java84
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java12
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java29
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java4
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java219
-rw-r--r--src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java2
39 files changed, 1422 insertions, 2760 deletions
diff --git a/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java b/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java
index 7faa3d3..95abce1 100644
--- a/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java
+++ b/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java
@@ -44,26 +44,21 @@ public class EditorPlaceHolder {
return null;
}
- try {
- editor.createEditor(mActivity, mContainer);
- editor.getImageShow().bindAsImageLoadListener();
- mContainer.setVisibility(View.VISIBLE);
- mContainer.removeAllViews();
- View eview = editor.getTopLevelView();
- ViewParent parent = eview.getParent();
-
- if (parent != null && parent instanceof FrameLayout) {
- ((FrameLayout) parent).removeAllViews();
- }
-
- mContainer.addView(eview);
- hideOldViews();
- editor.setVisibility(View.VISIBLE);
- return editor;
- } catch (Exception e) {
- e.printStackTrace();
+ editor.createEditor(mActivity, mContainer);
+ editor.getImageShow().bindAsImageLoadListener();
+ mContainer.setVisibility(View.VISIBLE);
+ mContainer.removeAllViews();
+ View eview = editor.getTopLevelView();
+ ViewParent parent = eview.getParent();
+
+ if (parent != null && parent instanceof FrameLayout) {
+ ((FrameLayout) parent).removeAllViews();
}
- return null;
+
+ mContainer.addView(eview);
+ hideOldViews();
+ editor.setVisibility(View.VISIBLE);
+ return editor;
}
public void setOldViews(Vector<ImageShow> views) {
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 0fca652..f0b1aa8 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -72,7 +72,7 @@ import com.android.gallery3d.filtershow.editors.BasicEditor;
import com.android.gallery3d.filtershow.editors.Editor;
import com.android.gallery3d.filtershow.editors.EditorCrop;
import com.android.gallery3d.filtershow.editors.EditorDraw;
-import com.android.gallery3d.filtershow.editors.EditorFlip;
+import com.android.gallery3d.filtershow.editors.EditorMirror;
import com.android.gallery3d.filtershow.editors.EditorManager;
import com.android.gallery3d.filtershow.editors.EditorPanel;
import com.android.gallery3d.filtershow.editors.EditorRedEye;
@@ -85,7 +85,6 @@ import com.android.gallery3d.filtershow.filters.FiltersManager;
import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.history.HistoryManager;
import com.android.gallery3d.filtershow.history.HistoryItem;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
import com.android.gallery3d.filtershow.imageshow.ImageCrop;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
@@ -394,7 +393,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mEditorPlaceHolder.addEditor(new EditorTinyPlanet());
mEditorPlaceHolder.addEditor(new EditorRedEye());
mEditorPlaceHolder.addEditor(new EditorCrop());
- mEditorPlaceHolder.addEditor(new EditorFlip());
+ mEditorPlaceHolder.addEditor(new EditorMirror());
mEditorPlaceHolder.addEditor(new EditorRotate());
mEditorPlaceHolder.addEditor(new EditorStraighten());
}
@@ -411,10 +410,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size);
Spline.setCurveHandle(curveHandle, curveHandleSize);
Spline.setCurveWidth((int) getPixelsFromDip(3));
-
- ImageCrop.setAspectTextSize((int) getPixelsFromDip(18));
- ImageCrop.setTouchTolerance((int) getPixelsFromDip(25));
- ImageCrop.setMinCropSize((int) getPixelsFromDip(55));
}
private void startLoadBitmap(Uri uri) {
@@ -494,6 +489,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
FilterRepresentation representation = copy.getRepresentation(filterRepresentation);
if (representation == null) {
copy.addFilter(filterRepresentation);
+ } else if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
+ filterRepresentation = representation;
} else {
if (filterRepresentation.allowsSingleInstanceOnly()) {
// Don't just update the filter representation. Centralize the
@@ -512,14 +509,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
return;
}
- // TODO: this check is needed because the GeometryMetadata doesn't quite
- // follow the same pattern as the other filters to update/sync their values.
- // We thus need to not call useFilterRepresentation() for now, as it
- // would override the current Geometry. Once GeometryMetadata is fixed,
- // let's remove the check and call useFilterRepresentation all the time.
- if (!(representation instanceof GeometryMetadata)) {
- useFilterRepresentation(representation);
- }
+ useFilterRepresentation(representation);
// show representation
Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
@@ -633,7 +623,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
if (!mShowingTinyPlanet) {
mCategoryFiltersAdapter.removeTinyPlanet();
}
- MasterImage.getImage().setOriginalGeometry(largeBitmap);
mCategoryLooksAdapter.imageLoaded();
mCategoryBordersAdapter.imageLoaded();
mCategoryGeometryAdapter.imageLoaded();
@@ -650,8 +639,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
if (mAction == TINY_PLANET_ACTION) {
showRepresentation(mCategoryFiltersAdapter.getTinyPlanet());
}
-
- MasterImage.getImage().notifyGeometryChange();
LoadHighresBitmapTask highresLoad = new LoadHighresBitmapTask();
highresLoad.execute();
super.onPostExecute(result);
@@ -937,7 +924,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
public void invalidateViews() {
for (ImageShow views : mImageViews) {
- views.invalidate();
views.updateImage();
}
}
diff --git a/src/com/android/gallery3d/filtershow/crop/BoundedRect.java b/src/com/android/gallery3d/filtershow/crop/BoundedRect.java
index 74ce7cd..13b8d6d 100644
--- a/src/com/android/gallery3d/filtershow/crop/BoundedRect.java
+++ b/src/com/android/gallery3d/filtershow/crop/BoundedRect.java
@@ -19,7 +19,7 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
-import com.android.gallery3d.filtershow.imageshow.GeometryMath;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
import java.util.Arrays;
@@ -134,7 +134,7 @@ public class BoundedRect {
};
float[] nearestSide = CropMath.closestSide(badCorner, outerCorners);
float[] correctionVec =
- GeometryMath.shortestVectorFromPointToLine(badCorner, nearestSide);
+ GeometryMathUtils.shortestVectorFromPointToLine(badCorner, nearestSide);
correction[0] += correctionVec[0];
correction[1] += correctionVec[1];
}
@@ -195,7 +195,7 @@ public class BoundedRect {
newInnerCorners[i], newInnerCorners[i + 1],
oldInnerCorners[i], oldInnerCorners[i + 1]
};
- float[] p = GeometryMath.lineIntersect(pathOfCorner, outerSide);
+ float[] p = GeometryMathUtils.lineIntersect(pathOfCorner, outerSide);
if (p == null) {
// lines are parallel or not well defined, so don't resize
p = new float[2];
@@ -288,7 +288,7 @@ public class BoundedRect {
newInnerCorners[i], newInnerCorners[i + 1],
oldInnerCorners[i], oldInnerCorners[i + 1]
};
- float[] p = GeometryMath.lineIntersect(l1, l2);
+ float[] p = GeometryMathUtils.lineIntersect(l1, l2);
if (p == null) {
// lines are parallel or not well defined, so set to old
// corner
diff --git a/src/com/android/gallery3d/filtershow/crop/CropMath.java b/src/com/android/gallery3d/filtershow/crop/CropMath.java
index 671554f..02c6531 100644
--- a/src/com/android/gallery3d/filtershow/crop/CropMath.java
+++ b/src/com/android/gallery3d/filtershow/crop/CropMath.java
@@ -20,7 +20,7 @@ import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
-import com.android.gallery3d.filtershow.imageshow.GeometryMath;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
import java.util.Arrays;
@@ -97,8 +97,8 @@ public class CropMath {
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);
+ array[x] = GeometryMathUtils.clamp(array[x], imageBound.left, imageBound.right);
+ array[x + 1] = GeometryMathUtils.clamp(array[x + 1], imageBound.top, imageBound.bottom);
}
}
@@ -119,8 +119,8 @@ public class CropMath {
corners[i], corners[(i + 1) % len],
corners[(i + 2) % len], corners[(i + 3) % len]
};
- float mag = GeometryMath.vectorLength(
- GeometryMath.shortestVectorFromPointToLine(point, line));
+ float mag = GeometryMathUtils.vectorLength(
+ GeometryMathUtils.shortestVectorFromPointToLine(point, line));
if (mag < oldMag) {
oldMag = mag;
bestLine = line;
diff --git a/src/com/android/gallery3d/filtershow/crop/CropObject.java b/src/com/android/gallery3d/filtershow/crop/CropObject.java
index bea3ffa..b98ed1b 100644
--- a/src/com/android/gallery3d/filtershow/crop/CropObject.java
+++ b/src/com/android/gallery3d/filtershow/crop/CropObject.java
@@ -19,10 +19,9 @@ package com.android.gallery3d.filtershow.crop;
import android.graphics.Rect;
import android.graphics.RectF;
-import com.android.gallery3d.filtershow.imageshow.GeometryMath;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
public class CropObject {
-
private BoundedRect mBoundedRect;
private float mAspectWidth = 1;
private float mAspectHeight = 1;
@@ -234,8 +233,8 @@ public class CropObject {
float[] disp = {
dx, dy
};
- float[] bUnit = GeometryMath.normalize(b);
- float sp = GeometryMath.scalarProjection(disp, bUnit);
+ float[] bUnit = GeometryMathUtils.normalize(b);
+ float sp = GeometryMathUtils.scalarProjection(disp, bUnit);
dx = sp * bUnit[0];
dy = sp * bUnit[1];
RectF newCrop = fixedCornerResize(crop, movingEdges, dx, dy);
diff --git a/src/com/android/gallery3d/filtershow/crop/CropView.java b/src/com/android/gallery3d/filtershow/crop/CropView.java
index 0a7950c..bbb7cfd 100644
--- a/src/com/android/gallery3d/filtershow/crop/CropView.java
+++ b/src/com/android/gallery3d/filtershow/crop/CropView.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -50,8 +49,8 @@ public class CropView extends View {
private NinePatchDrawable mShadow;
private CropObject mCropObj = null;
- private final Drawable mCropIndicator;
- private final int mIndicatorSize;
+ private Drawable mCropIndicator;
+ private int mIndicatorSize;
private int mRotation = 0;
private boolean mMovingBlock = false;
private Matrix mDisplayMatrix = null;
@@ -80,8 +79,22 @@ public class CropView extends View {
private Mode mState = Mode.NONE;
+ public CropView(Context context) {
+ super(context);
+ setup(context);
+ }
+
public CropView(Context context, AttributeSet attrs) {
super(context, attrs);
+ setup(context);
+ }
+
+ public CropView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setup(context);
+ }
+
+ private void setup(Context context) {
Resources rsc = context.getResources();
mShadow = (NinePatchDrawable) rsc.getDrawable(R.drawable.geometry_shadow);
mCropIndicator = rsc.getDrawable(R.drawable.camera_crop);
diff --git a/src/com/android/gallery3d/filtershow/editors/Editor.java b/src/com/android/gallery3d/filtershow/editors/Editor.java
index 9539d65..a9e56e0 100644
--- a/src/com/android/gallery3d/filtershow/editors/Editor.java
+++ b/src/com/android/gallery3d/filtershow/editors/Editor.java
@@ -31,13 +31,15 @@ import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.controller.Control;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Base class for Editors Must contain a mImageShow and a top level view
*/
@@ -51,6 +53,7 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
protected Button mFilterTitle;
protected int mID;
private final String LOGTAG = "Editor";
+ protected boolean mChangesGeometry = false;
protected FilterRepresentation mLocalRepresentation = null;
protected byte mShowParameter = SHOW_VALUE_UNDEFINED;
private Button mButton;
@@ -206,12 +209,50 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
return mLocalRepresentation;
}
+ /**
+ * Call this to update the preset in MasterImage with the current representation
+ * returned by getLocalRepresentation. This causes the preview bitmap to be
+ * regenerated.
+ */
public void commitLocalRepresentation() {
+ commitLocalRepresentation(getLocalRepresentation());
+ }
+
+ /**
+ * Call this to update the preset in MasterImage with a given representation.
+ * This causes the preview bitmap to be regenerated.
+ */
+ public void commitLocalRepresentation(FilterRepresentation rep) {
+ ArrayList<FilterRepresentation> filter = new ArrayList<FilterRepresentation>(1);
+ filter.add(rep);
+ commitLocalRepresentation(filter);
+ }
+
+ /**
+ * Call this to update the preset in MasterImage with a collection of FilterRepresnations.
+ * This causes the preview bitmap to be regenerated.
+ */
+ public void commitLocalRepresentation(Collection<FilterRepresentation> reps) {
ImagePreset preset = MasterImage.getImage().getPreset();
- preset.updateFilterRepresentation(getLocalRepresentation());
+ preset.updateFilterRepresentations(reps);
if (mButton != null) {
updateText();
}
+ if (mChangesGeometry) {
+ // Regenerate both the filtered and the geometry-only bitmaps
+ MasterImage.getImage().updatePresets(true);
+ } else {
+ // Regenerate only the filtered bitmap.
+ MasterImage.getImage().invalidateFiltersOnly();
+ }
+ preset.fillImageStateAdapter(MasterImage.getImage().getState());
+ }
+
+ /**
+ * This is called in response to a click to apply and leave the editor.
+ */
+ public void finalApplyCalled() {
+ commitLocalRepresentation();
}
protected void updateText() {
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
index ec6e30b..511d4ff 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
@@ -17,6 +17,8 @@
package com.android.gallery3d.filtershow.editors;
import android.content.Context;
+import android.util.Log;
+import android.util.SparseArray;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
@@ -26,43 +28,77 @@ import android.widget.LinearLayout;
import android.widget.PopupMenu;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.crop.CropExtras;
+import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.imageshow.ImageCrop;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
public class EditorCrop extends Editor implements EditorInfo {
+ public static final String TAG = EditorCrop.class.getSimpleName();
public static final int ID = R.id.editorCrop;
- private static final String LOGTAG = "EditorCrop";
- ImageCrop mImageCrop;
+ // Holder for an aspect ratio it's string id
+ protected static final class AspectInfo {
+ int mAspectX;
+ int mAspectY;
+ int mStringId;
+ AspectInfo(int stringID, int x, int y) {
+ mStringId = stringID;
+ mAspectX = x;
+ mAspectY = y;
+ }
+ };
+
+ // Mapping from menu id to aspect ratio
+ protected static final SparseArray<AspectInfo> sAspects;
+ static {
+ sAspects = new SparseArray<AspectInfo>();
+ sAspects.put(R.id.crop_menu_1to1, new AspectInfo(R.string.aspect1to1_effect, 1, 1));
+ sAspects.put(R.id.crop_menu_4to3, new AspectInfo(R.string.aspect4to3_effect, 4, 3));
+ sAspects.put(R.id.crop_menu_3to4, new AspectInfo(R.string.aspect3to4_effect, 3, 4));
+ sAspects.put(R.id.crop_menu_5to7, new AspectInfo(R.string.aspect5to7_effect, 5, 7));
+ sAspects.put(R.id.crop_menu_7to5, new AspectInfo(R.string.aspect7to5_effect, 7, 5));
+ sAspects.put(R.id.crop_menu_none, new AspectInfo(R.string.aspectNone_effect, 0, 0));
+ sAspects.put(R.id.crop_menu_original, new AspectInfo(R.string.aspectOriginal_effect, 0, 0));
+ }
+
+ protected ImageCrop mImageCrop;
private String mAspectString = "";
- private boolean mCropActionFlag = false;
- private CropExtras mCropExtras = null;
public EditorCrop() {
super(ID);
+ mChangesGeometry = true;
}
@Override
public void createEditor(Context context, FrameLayout frameLayout) {
super.createEditor(context, frameLayout);
if (mImageCrop == null) {
- // TODO: need this for now because there's extra state in ImageCrop.
- // all the state instead should be in the representation.
- // Same thing for the other geometry editors.
mImageCrop = new ImageCrop(context);
}
mView = mImageShow = mImageCrop;
- mImageCrop.bindAsImageLoadListener();
mImageCrop.setEditor(this);
- mImageCrop.syncLocalToMasterGeometry();
- mImageCrop.setCropActionFlag(mCropActionFlag);
- if (mCropActionFlag) {
- mImageCrop.setExtras(mCropExtras);
- mImageCrop.setAspectString(mAspectString);
- mImageCrop.clear();
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ MasterImage master = MasterImage.getImage();
+ master.setCurrentFilterRepresentation(master.getPreset()
+ .getFilterWithSerializationName(FilterCropRepresentation.SERIALIZATION_NAME));
+ super.reflectCurrentFilter();
+ FilterRepresentation rep = getLocalRepresentation();
+ if (rep == null || rep instanceof FilterCropRepresentation) {
+ mImageCrop.setFilterCropRepresentation((FilterCropRepresentation) rep);
} else {
- mImageCrop.setExtras(null);
+ Log.w(TAG, "Could not reflect current filter, not of type: "
+ + FilterCropRepresentation.class.getSimpleName());
}
+ mImageCrop.invalidate();
+ }
+
+ @Override
+ public void finalApplyCalled() {
+ commitLocalRepresentation(mImageCrop.getFinalRepresentation());
}
@Override
@@ -70,27 +106,36 @@ public class EditorCrop extends Editor implements EditorInfo {
Button view = (Button) accessoryViewList.findViewById(R.id.applyEffect);
view.setText(mContext.getString(R.string.crop));
view.setOnClickListener(new OnClickListener() {
-
- @Override
+ @Override
public void onClick(View arg0) {
showPopupMenu(accessoryViewList);
}
});
}
- private void showPopupMenu(LinearLayout accessoryViewList) {
- final Button button = (Button) accessoryViewList.findViewById(
- R.id.applyEffect);
- if (button == null) {
- return;
+ private void changeCropAspect(int itemId) {
+ AspectInfo info = sAspects.get(itemId);
+ if (info == null) {
+ throw new IllegalArgumentException("Invalid resource ID: " + itemId);
}
+ if (itemId == R.id.crop_menu_original) {
+ mImageCrop.applyOriginalAspect();
+ } else if (itemId == R.id.crop_menu_none) {
+ mImageCrop.applyFreeAspect();
+ } else {
+ mImageCrop.applyAspect(info.mAspectX, info.mAspectY);
+ }
+ setAspectString(mContext.getString(info.mStringId));
+ }
+
+ private void showPopupMenu(LinearLayout accessoryViewList) {
+ final Button button = (Button) accessoryViewList.findViewById(R.id.applyEffect);
final PopupMenu popupMenu = new PopupMenu(mImageShow.getActivity(), button);
popupMenu.getMenuInflater().inflate(R.menu.filtershow_menu_crop, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
-
@Override
public boolean onMenuItemClick(MenuItem item) {
- mImageCrop.setAspectButton(item.getItemId());
+ changeCropAspect(item.getItemId());
return true;
}
});
@@ -117,16 +162,7 @@ public class EditorCrop extends Editor implements EditorInfo {
return true;
}
- public void setExtras(CropExtras cropExtras) {
- mCropExtras = cropExtras;
- }
-
- public void setAspectString(String s) {
+ private void setAspectString(String s) {
mAspectString = s;
}
-
- public void setCropActionFlag(boolean b) {
- mCropActionFlag = b;
- }
-
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorFlip.java b/src/com/android/gallery3d/filtershow/editors/EditorMirror.java
index 6707004..d6d9ee7 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorFlip.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorMirror.java
@@ -17,6 +17,7 @@
package com.android.gallery3d.filtershow.editors;
import android.content.Context;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -24,27 +25,45 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.imageshow.ImageFlip;
+import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageMirror;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
-public class EditorFlip extends Editor implements EditorInfo {
- public static final String LOGTAG = "EditorFlip";
+public class EditorMirror extends Editor implements EditorInfo {
+ public static final String TAG = EditorMirror.class.getSimpleName();
public static final int ID = R.id.editorFlip;
- ImageFlip mImageFlip;
+ ImageMirror mImageMirror;
- public EditorFlip() {
+ public EditorMirror() {
super(ID);
+ mChangesGeometry = true;
}
@Override
public void createEditor(Context context, FrameLayout frameLayout) {
super.createEditor(context, frameLayout);
- if (mImageFlip == null) {
- mImageFlip = new ImageFlip(context);
+ if (mImageMirror == null) {
+ mImageMirror = new ImageMirror(context);
}
- mView = mImageShow = mImageFlip;
- mImageFlip.bindAsImageLoadListener();
- mImageFlip.setEditor(this);
- mImageFlip.syncLocalToMasterGeometry();
+ mView = mImageShow = mImageMirror;
+ mImageMirror.setEditor(this);
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ MasterImage master = MasterImage.getImage();
+ master.setCurrentFilterRepresentation(master.getPreset()
+ .getFilterWithSerializationName(FilterMirrorRepresentation.SERIALIZATION_NAME));
+ super.reflectCurrentFilter();
+ FilterRepresentation rep = getLocalRepresentation();
+ if (rep == null || rep instanceof FilterMirrorRepresentation) {
+ mImageMirror.setFilterMirrorRepresentation((FilterMirrorRepresentation) rep);
+ } else {
+ Log.w(TAG, "Could not reflect current filter, not of type: "
+ + FilterMirrorRepresentation.class.getSimpleName());
+ }
+ mImageMirror.invalidate();
}
@Override
@@ -53,13 +72,17 @@ public class EditorFlip extends Editor implements EditorInfo {
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
- mImageFlip.flip();
- mImageFlip.saveAndSetPreset();
+ mImageMirror.flip();
}
});
}
@Override
+ public void finalApplyCalled() {
+ commitLocalRepresentation(mImageMirror.getFinalRepresentation());
+ }
+
+ @Override
public int getTextId() {
return R.string.mirror;
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
index 40dfccd..bc4ca6a 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
@@ -88,17 +88,8 @@ public class EditorPanel extends Fragment {
activity.backToMain();
}
});
- applyButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- MasterImage.getImage().invalidateFiltersOnly();
- FilterShowActivity activity = (FilterShowActivity) getActivity();
- activity.backToMain();
- }
- });
Button toggleState = (Button) mMainView.findViewById(R.id.toggle_state);
-
mEditor = activity.getEditor(mEditorID);
if (mEditor != null) {
mEditor.setUpEditorUI(actionControl, editControl, editTitle, toggleState);
@@ -107,6 +98,14 @@ public class EditorPanel extends Fragment {
mEditor.openUtilityPanel((LinearLayout) actionControl);
}
}
+ applyButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FilterShowActivity activity = (FilterShowActivity) getActivity();
+ mEditor.finalApplyCalled();
+ activity.backToMain();
+ }
+ });
showImageStatePanel(activity.isShowingImageStatePanel());
return mMainView;
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorRotate.java b/src/com/android/gallery3d/filtershow/editors/EditorRotate.java
index e66be2c..9452bf0 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorRotate.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorRotate.java
@@ -17,6 +17,7 @@
package com.android.gallery3d.filtershow.editors;
import android.content.Context;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -24,15 +25,19 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
import com.android.gallery3d.filtershow.imageshow.ImageRotate;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
public class EditorRotate extends Editor implements EditorInfo {
- public static final String LOGTAG = "EditorRotate";
+ public static final String TAG = EditorRotate.class.getSimpleName();
public static final int ID = R.id.editorRotate;
ImageRotate mImageRotate;
public EditorRotate() {
super(ID);
+ mChangesGeometry = true;
}
@Override
@@ -42,9 +47,23 @@ public class EditorRotate extends Editor implements EditorInfo {
mImageRotate = new ImageRotate(context);
}
mView = mImageShow = mImageRotate;
- mImageRotate.bindAsImageLoadListener();
mImageRotate.setEditor(this);
- mImageRotate.syncLocalToMasterGeometry();
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ MasterImage master = MasterImage.getImage();
+ master.setCurrentFilterRepresentation(master.getPreset()
+ .getFilterWithSerializationName(FilterRotateRepresentation.SERIALIZATION_NAME));
+ super.reflectCurrentFilter();
+ FilterRepresentation rep = getLocalRepresentation();
+ if (rep == null || rep instanceof FilterRotateRepresentation) {
+ mImageRotate.setFilterRotateRepresentation((FilterRotateRepresentation) rep);
+ } else {
+ Log.w(TAG, "Could not reflect current filter, not of type: "
+ + FilterRotateRepresentation.class.getSimpleName());
+ }
+ mImageRotate.invalidate();
}
@Override
@@ -54,13 +73,19 @@ public class EditorRotate extends Editor implements EditorInfo {
@Override
public void onClick(View arg0) {
mImageRotate.rotate();
- button.setText(mContext.getString(getTextId()) + " " + mImageRotate.getLocalValue());
- mImageRotate.saveAndSetPreset();
+ String displayVal = mContext.getString(getTextId()) + " "
+ + mImageRotate.getLocalValue();
+ button.setText(displayVal);
}
});
}
@Override
+ public void finalApplyCalled() {
+ commitLocalRepresentation(mImageRotate.getFinalRepresentation());
+ }
+
+ @Override
public int getTextId() {
return R.string.rotate;
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorStraighten.java b/src/com/android/gallery3d/filtershow/editors/EditorStraighten.java
index 40333aa..ff84ba8 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorStraighten.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorStraighten.java
@@ -17,24 +17,26 @@
package com.android.gallery3d.filtershow.editors;
import android.content.Context;
-import android.view.View;
+import android.util.Log;
import android.widget.FrameLayout;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
public class EditorStraighten extends Editor implements EditorInfo {
+ public static final String TAG = EditorStraighten.class.getSimpleName();
public static final int ID = R.id.editorStraighten;
ImageStraighten mImageStraighten;
- GeometryMetadata mGeometryMetadata;
public EditorStraighten() {
super(ID);
mShowParameter = SHOW_VALUE_INT;
+ mChangesGeometry = true;
}
- // TODO use filter reflection like
@Override
public String calculateUserMessage(Context context, String effectName, Object parameterValue) {
String apply = context.getString(R.string.apply_effect);
@@ -49,9 +51,29 @@ public class EditorStraighten extends Editor implements EditorInfo {
mImageStraighten = new ImageStraighten(context);
}
mView = mImageShow = mImageStraighten;
- mImageStraighten.bindAsImageLoadListener();
mImageStraighten.setEditor(this);
- mImageStraighten.syncLocalToMasterGeometry();
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ MasterImage master = MasterImage.getImage();
+ master.setCurrentFilterRepresentation(master.getPreset().getFilterWithSerializationName(
+ FilterStraightenRepresentation.SERIALIZATION_NAME));
+ super.reflectCurrentFilter();
+ FilterRepresentation rep = getLocalRepresentation();
+ if (rep == null || rep instanceof FilterStraightenRepresentation) {
+ mImageStraighten
+ .setFilterStraightenRepresentation((FilterStraightenRepresentation) rep);
+ } else {
+ Log.w(TAG, "Could not reflect current filter, not of type: "
+ + FilterStraightenRepresentation.class.getSimpleName());
+ }
+ mImageStraighten.invalidate();
+ }
+
+ @Override
+ public void finalApplyCalled() {
+ commitLocalRepresentation(mImageStraighten.getFinalRepresentation());
}
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
index 2205b4d..4708abb 100644
--- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
+++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
@@ -20,7 +20,10 @@ import android.content.res.Resources;
import android.util.Log;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
+import com.android.gallery3d.filtershow.editors.EditorCrop;
+import com.android.gallery3d.filtershow.editors.EditorMirror;
+import com.android.gallery3d.filtershow.editors.EditorRotate;
+import com.android.gallery3d.filtershow.editors.EditorStraighten;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
import java.util.ArrayList;
@@ -138,7 +141,6 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
filters.add(ImageFilterFx.class);
filters.add(ImageFilterBorder.class);
filters.add(ImageFilterParametricBorder.class);
- filters.add(ImageFilterGeometry.class);
}
public ArrayList<FilterRepresentation> getLooks() {
@@ -238,8 +240,13 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
}
public void addTools(Context context) {
- GeometryMetadata geo = new GeometryMetadata();
- int[] editorsId = geo.getEditorIds();
+
+ int[] editorsId = {
+ EditorCrop.ID,
+ EditorStraighten.ID,
+ EditorRotate.ID,
+ EditorMirror.ID
+ };
int[] textId = {
R.string.crop,
@@ -255,9 +262,16 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
R.drawable.filtershow_button_geometry_flip
};
+ FilterRepresentation[] geometryFilters = {
+ new FilterCropRepresentation(),
+ new FilterStraightenRepresentation(),
+ new FilterRotateRepresentation(),
+ new FilterMirrorRepresentation()
+ };
+
for (int i = 0; i < editorsId.length; i++) {
int editorId = editorsId[i];
- GeometryMetadata geometry = new GeometryMetadata(geo);
+ FilterRepresentation geometry = geometryFilters[i];
geometry.setEditorId(editorId);
geometry.setTextId(textId[i]);
geometry.setOverlayId(overlayId[i]);
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java
index fea8b21..c1bd7b3 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java
@@ -28,14 +28,13 @@ import java.io.IOException;
public class FilterCropRepresentation extends FilterRepresentation {
public static final String SERIALIZATION_NAME = "CROP";
public static final String[] BOUNDS = {
- "C0", "C1", "C2", "C3", "I0", "I1", "I2", "I3"
+ "C0", "C1", "C2", "C3"
};
private static final String TAG = FilterCropRepresentation.class.getSimpleName();
- RectF mCrop = new RectF();
- RectF mImage = new RectF();
+ RectF mCrop = getNil();
- public FilterCropRepresentation(RectF crop, RectF image) {
+ public FilterCropRepresentation(RectF crop) {
super(FilterCropRepresentation.class.getSimpleName());
setSerializationName(SERIALIZATION_NAME);
setShowParameterValue(true);
@@ -44,20 +43,18 @@ public class FilterCropRepresentation extends FilterRepresentation {
setTextId(R.string.crop);
setEditorId(EditorCrop.ID);
setCrop(crop);
- setImage(image);
}
public FilterCropRepresentation(FilterCropRepresentation m) {
- this(m.getCrop(), m.getImage());
+ this(m.mCrop);
}
public FilterCropRepresentation() {
- this(new RectF(), new RectF());
+ this(sNilRect);
}
public void set(FilterCropRepresentation r) {
mCrop.set(r.mCrop);
- mImage.set(r.mImage);
}
@Override
@@ -69,11 +66,7 @@ public class FilterCropRepresentation extends FilterRepresentation {
if (mCrop.bottom != crop.mCrop.bottom
|| mCrop.left != crop.mCrop.left
|| mCrop.right != crop.mCrop.right
- || mCrop.top != crop.mCrop.top
- || mImage.bottom != crop.mImage.bottom
- || mImage.left != crop.mImage.left
- || mImage.right != crop.mImage.right
- || mImage.top != crop.mImage.top) {
+ || mCrop.top != crop.mCrop.top) {
return false;
}
return true;
@@ -94,19 +87,26 @@ public class FilterCropRepresentation extends FilterRepresentation {
mCrop.set(crop);
}
- public RectF getImage() {
- return new RectF(mImage);
+ /**
+ * Takes a crop rect contained by [0, 0, 1, 1] and scales it by the height
+ * and width of the image rect.
+ */
+ public static void findScaledCrop(RectF crop, int bitmapWidth, int bitmapHeight) {
+ crop.left *= bitmapWidth;
+ crop.top *= bitmapHeight;
+ crop.right *= bitmapWidth;
+ crop.bottom *= bitmapHeight;
}
- public void getImage(RectF r) {
- r.set(mImage);
- }
-
- public void setImage(RectF image) {
- if (image == null) {
- throw new IllegalArgumentException("Argument to setImage is null");
- }
- mImage.set(image);
+ /**
+ * Takes crop rect and normalizes it by scaling down by the height and width
+ * of the image rect.
+ */
+ public static void findNormalizedCrop(RectF crop, int bitmapWidth, int bitmapHeight) {
+ crop.left /= bitmapWidth;
+ crop.top /= bitmapHeight;
+ crop.right /= bitmapWidth;
+ crop.bottom /= bitmapHeight;
}
@Override
@@ -115,7 +115,7 @@ public class FilterCropRepresentation extends FilterRepresentation {
}
@Override
- public FilterRepresentation copy(){
+ public FilterRepresentation copy() {
return new FilterCropRepresentation(this);
}
@@ -134,12 +134,17 @@ public class FilterCropRepresentation extends FilterRepresentation {
throw new IllegalArgumentException("calling useParametersFrom with incompatible types!");
}
setCrop(((FilterCropRepresentation) a).mCrop);
- setImage(((FilterCropRepresentation) a).mImage);
}
+ private static final RectF sNilRect = new RectF(0, 0, 1, 1);
+
@Override
public boolean isNil() {
- return mCrop.equals(mImage);
+ return mCrop.equals(sNilRect);
+ }
+
+ public static RectF getNil() {
+ return new RectF(sNilRect);
}
@Override
@@ -149,10 +154,6 @@ public class FilterCropRepresentation extends FilterRepresentation {
writer.name(BOUNDS[1]).value(mCrop.top);
writer.name(BOUNDS[2]).value(mCrop.right);
writer.name(BOUNDS[3]).value(mCrop.bottom);
- writer.name(BOUNDS[4]).value(mImage.left);
- writer.name(BOUNDS[5]).value(mImage.top);
- writer.name(BOUNDS[6]).value(mImage.right);
- writer.name(BOUNDS[7]).value(mImage.bottom);
writer.endObject();
}
@@ -169,14 +170,6 @@ public class FilterCropRepresentation extends FilterRepresentation {
mCrop.right = (float) reader.nextDouble();
} else if (BOUNDS[3].equals(name)) {
mCrop.bottom = (float) reader.nextDouble();
- } else if (BOUNDS[4].equals(name)) {
- mImage.left = (float) reader.nextDouble();
- } else if (BOUNDS[5].equals(name)) {
- mImage.top = (float) reader.nextDouble();
- } else if (BOUNDS[6].equals(name)) {
- mImage.right = (float) reader.nextDouble();
- } else if (BOUNDS[7].equals(name)) {
- mImage.bottom = (float) reader.nextDouble();
} else {
reader.skipValue();
}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java
index 22a15f2..8dcff0d 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java
@@ -21,7 +21,7 @@ import android.util.JsonWriter;
import android.util.Log;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.editors.EditorFlip;
+import com.android.gallery3d.filtershow.editors.EditorMirror;
import java.io.IOException;
@@ -30,7 +30,7 @@ public class FilterMirrorRepresentation extends FilterRepresentation {
private static final String SERIALIZATION_MIRROR_VALUE = "value";
private static final String TAG = FilterMirrorRepresentation.class.getSimpleName();
- Mirror mMirror = Mirror.NONE;
+ Mirror mMirror;
public enum Mirror {
NONE('N'), VERTICAL('V'), HORIZONTAL('H'), BOTH('B');
@@ -67,7 +67,7 @@ public class FilterMirrorRepresentation extends FilterRepresentation {
setFilterClass(FilterMirrorRepresentation.class);
setFilterType(FilterRepresentation.TYPE_GEOMETRY);
setTextId(R.string.mirror);
- setEditorId(EditorFlip.ID);
+ setEditorId(EditorMirror.ID);
setMirror(mirror);
}
@@ -76,7 +76,7 @@ public class FilterMirrorRepresentation extends FilterRepresentation {
}
public FilterMirrorRepresentation() {
- this(Mirror.NONE);
+ this(getNil());
}
@Override
@@ -85,7 +85,7 @@ public class FilterMirrorRepresentation extends FilterRepresentation {
return false;
}
FilterMirrorRepresentation mirror = (FilterMirrorRepresentation) rep;
- if (mirror.mMirror.value() != mirror.mMirror.value()) {
+ if (mMirror != mirror.mMirror) {
return false;
}
return true;
@@ -106,6 +106,23 @@ public class FilterMirrorRepresentation extends FilterRepresentation {
mMirror = mirror;
}
+ public void cycle() {
+ switch (mMirror) {
+ case NONE:
+ mMirror = Mirror.HORIZONTAL;
+ break;
+ case HORIZONTAL:
+ mMirror = Mirror.VERTICAL;
+ break;
+ case VERTICAL:
+ mMirror = Mirror.BOTH;
+ break;
+ case BOTH:
+ mMirror = Mirror.NONE;
+ break;
+ }
+ }
+
@Override
public boolean allowsSingleInstanceOnly() {
return true;
@@ -135,7 +152,11 @@ public class FilterMirrorRepresentation extends FilterRepresentation {
@Override
public boolean isNil() {
- return mMirror == Mirror.NONE;
+ return mMirror == getNil();
+ }
+
+ public static Mirror getNil() {
+ return Mirror.NONE;
}
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java
index d5f3a5b..eb89de0 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java
@@ -30,7 +30,7 @@ public class FilterRotateRepresentation extends FilterRepresentation {
public static final String SERIALIZATION_ROTATE_VALUE = "value";
private static final String TAG = FilterRotateRepresentation.class.getSimpleName();
- Rotation mRotation = Rotation.ZERO;
+ Rotation mRotation;
public enum Rotation {
ZERO(0), NINETY(90), ONE_EIGHTY(180), TWO_SEVENTY(270);
@@ -76,13 +76,30 @@ public class FilterRotateRepresentation extends FilterRepresentation {
}
public FilterRotateRepresentation() {
- this(Rotation.ZERO);
+ this(getNil());
}
public Rotation getRotation() {
return mRotation;
}
+ public void rotateCW() {
+ switch(mRotation) {
+ case ZERO:
+ mRotation = Rotation.NINETY;
+ break;
+ case NINETY:
+ mRotation = Rotation.ONE_EIGHTY;
+ break;
+ case ONE_EIGHTY:
+ mRotation = Rotation.TWO_SEVENTY;
+ break;
+ case TWO_SEVENTY:
+ mRotation = Rotation.ZERO;
+ break;
+ }
+ }
+
public void set(FilterRotateRepresentation r) {
mRotation = r.mRotation;
}
@@ -123,7 +140,11 @@ public class FilterRotateRepresentation extends FilterRepresentation {
@Override
public boolean isNil() {
- return mRotation == Rotation.ZERO;
+ return mRotation == getNil();
+ }
+
+ public static Rotation getNil() {
+ return Rotation.ZERO;
}
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java
index 890f1cf..94c9497 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java
@@ -29,6 +29,8 @@ public class FilterStraightenRepresentation extends FilterRepresentation {
public static final String SERIALIZATION_NAME = "STRAIGHTEN";
public static final String SERIALIZATION_STRAIGHTEN_VALUE = "value";
private static final String TAG = FilterStraightenRepresentation.class.getSimpleName();
+ public static final int MAX_STRAIGHTEN_ANGLE = 45;
+ public static final int MIN_STRAIGHTEN_ANGLE = -45;
float mStraighten;
@@ -48,7 +50,7 @@ public class FilterStraightenRepresentation extends FilterRepresentation {
}
public FilterStraightenRepresentation() {
- this(0);
+ this(getNil());
}
public void set(FilterStraightenRepresentation r) {
@@ -73,7 +75,7 @@ public class FilterStraightenRepresentation extends FilterRepresentation {
public void setStraighten(float straighten) {
if (!rangeCheck(straighten)) {
- straighten = Math.min(Math.max(straighten, -45), 45);
+ straighten = Math.min(Math.max(straighten, MIN_STRAIGHTEN_ANGLE), MAX_STRAIGHTEN_ANGLE);
}
mStraighten = straighten;
}
@@ -107,7 +109,11 @@ public class FilterStraightenRepresentation extends FilterRepresentation {
@Override
public boolean isNil() {
- return mStraighten == 0;
+ return mStraighten == getNil();
+ }
+
+ public static float getNil() {
+ return 0;
}
@Override
@@ -124,7 +130,7 @@ public class FilterStraightenRepresentation extends FilterRepresentation {
while (reader.hasNext()) {
String name = reader.nextName();
if (SERIALIZATION_STRAIGHTEN_VALUE.equals(name)) {
- int s = reader.nextInt();
+ float s = (float) reader.nextDouble();
if (rangeCheck(s)) {
setStraighten(s);
unset = false;
@@ -139,7 +145,7 @@ public class FilterStraightenRepresentation extends FilterRepresentation {
reader.endObject();
}
- private boolean rangeCheck(float s) {
+ private boolean rangeCheck(double s) {
if (s < -45 || s > 45) {
return false;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index 050dc43..4371374 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -22,10 +22,9 @@ import android.graphics.Matrix;
import android.support.v8.renderscript.Allocation;
import android.widget.Toast;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.pipeline.FilterEnvironment;
-import com.android.gallery3d.filtershow.pipeline.ImagePreset;
public abstract class ImageFilter implements Cloneable {
private FilterEnvironment mEnvironment = null;
@@ -89,13 +88,8 @@ public abstract class ImageFilter implements Cloneable {
}
protected Matrix getOriginalToScreenMatrix(int w, int h) {
- ImagePreset preset = getEnvironment().getImagePreset();
- GeometryMetadata geo = getEnvironment().getImagePreset().getGeometry();
- Matrix originalToScreen = geo.getOriginalToScreen(true,
- MasterImage.getImage().getOriginalBounds().width(),
- MasterImage.getImage().getOriginalBounds().height(),
- w, h);
- return originalToScreen;
+ return GeometryMathUtils.getImageToScreenMatrix(getEnvironment().getImagePreset()
+ .getGeometryFilters(), true, MasterImage.getImage().getOriginalBounds(), w, h);
}
public void setEnvironment(FilterEnvironment environment) {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
deleted file mode 100644
index 3c323e1..0000000
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
+++ /dev/null
@@ -1,117 +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.filters;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.util.Log;
-
-import com.android.gallery3d.filtershow.crop.CropExtras;
-import com.android.gallery3d.filtershow.imageshow.GeometryMath;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
-
-public class ImageFilterGeometry extends ImageFilter {
- private final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
- private GeometryMetadata mGeometry = null;
- private static final String LOGTAG = "ImageFilterGeometry";
- private static final boolean LOGV = false;
- private static final int BOTH = 3;
- private static final int VERTICAL = 2;
- private static final int HORIZONTAL = 1;
- private static final int NINETY = 1;
- private static final int ONE_EIGHTY = 2;
- private static final int TWO_SEVENTY = 3;
-
- public ImageFilterGeometry() {
- mName = "Geometry";
- }
-
- @Override
- public ImageFilter clone() throws CloneNotSupportedException {
- // FIXME: clone() should not be needed. Remove when we fix geometry.
- ImageFilterGeometry filter = (ImageFilterGeometry) super.clone();
- return filter;
- }
-
- native protected void nativeApplyFilterFlip(Bitmap src, int srcWidth, int srcHeight,
- Bitmap dst, int dstWidth, int dstHeight, int flip);
-
- native protected void nativeApplyFilterRotate(Bitmap src, int srcWidth, int srcHeight,
- Bitmap dst, int dstWidth, int dstHeight, int rotate);
-
- native protected void nativeApplyFilterCrop(Bitmap src, int srcWidth, int srcHeight,
- Bitmap dst, int dstWidth, int dstHeight, int offsetWidth, int offsetHeight);
-
- native protected void nativeApplyFilterStraighten(Bitmap src, int srcWidth, int srcHeight,
- Bitmap dst, int dstWidth, int dstHeight, float straightenAngle);
-
- @Override
- public void useRepresentation(FilterRepresentation representation) {
- mGeometry = (GeometryMetadata) representation;
- }
-
- @Override
- public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
- // TODO: implement bilinear or bicubic here... for now, just use
- // canvas to do a simple implementation...
- // TODO: and be more memory efficient! (do it in native?)
- RectF cb = mGeometry.getPreviewCropBounds();
- RectF pb = mGeometry.getPhotoBounds();
- if (cb.width() == 0 || cb.height() == 0 || pb.width() == 0 || pb.height() == 0) {
- Log.w(LOGTAG, "Cannot apply geometry: geometry metadata has not been initialized");
- return bitmap;
- }
-
- Rect cropBounds = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
- RectF crop = mGeometry.getCropBounds(bitmap);
- if (crop.width() > 0 && crop.height() > 0)
- cropBounds = GeometryMath.roundNearest(crop);
-
- int width = cropBounds.width();
- int height = cropBounds.height();
-
- if (mGeometry.hasSwitchedWidthHeight()){
- int temp = width;
- width = height;
- height = temp;
- }
-
- Bitmap temp = null;
- temp = Bitmap.createBitmap(width, height, mConfig);
-
- float[] displayCenter = {
- temp.getWidth() / 2f, temp.getHeight() / 2f
- };
-
- Matrix m1 = mGeometry.buildTotalXform(bitmap.getWidth(), bitmap.getHeight(), displayCenter);
-
- m1.postScale(1, 1, displayCenter[0], displayCenter[1]);
-
- Canvas canvas = new Canvas(temp);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
- canvas.drawBitmap(bitmap, m1, paint);
- return temp;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java
deleted file mode 100644
index a3bb6f9..0000000
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java
+++ /dev/null
@@ -1,89 +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.filters;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-
-public class ImageFilterStraighten extends ImageFilter {
- private final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
- private float mRotation;
- private float mZoomFactor;
-
- public ImageFilterStraighten() {
- mName = "Straighten";
- }
-
- @Override
- public ImageFilter clone() throws CloneNotSupportedException {
- // FIXME: clone() should not be needed. Remove when we fix geometry.
- ImageFilterStraighten filter = (ImageFilterStraighten) super.clone();
- filter.mRotation = mRotation;
- filter.mZoomFactor = mZoomFactor;
- return filter;
- }
-
- public ImageFilterStraighten(float rotation, float zoomFactor) {
- mRotation = rotation;
- mZoomFactor = zoomFactor;
- }
-
- public void setRotation(float rotation) {
- mRotation = rotation;
- }
-
- public void setRotationZoomFactor(float zoomFactor) {
- mZoomFactor = zoomFactor;
- }
-
- @Override
- public void useRepresentation(FilterRepresentation representation) {
-
- }
-
- @Override
- public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
- // TODO: implement bilinear or bicubic here... for now, just use
- // canvas to do a simple implementation...
- // TODO: and be more memory efficient! (do it in native?)
-
- Bitmap temp = bitmap.copy(mConfig, true);
- Canvas canvas = new Canvas(temp);
- canvas.save();
- Rect bounds = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
- float w = temp.getWidth();
- float h = temp.getHeight();
- float mw = temp.getWidth() / 2.0f;
- float mh = temp.getHeight() / 2.0f;
-
- canvas.scale(mZoomFactor, mZoomFactor, mw, mh);
- canvas.rotate(mRotation, mw, mh);
- canvas.drawBitmap(bitmap, bounds, bounds, new Paint());
- canvas.restore();
-
- int[] pixels = new int[(int) (w * h)];
- temp.getPixels(pixels, 0, (int) w, 0, 0, (int) w, (int) h);
- bitmap.setPixels(pixels, 0, (int) w, 0, 0, (int) w, (int) h);
- temp.recycle();
- temp = null;
- pixels = null;
- return bitmap;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryListener.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryListener.java
deleted file mode 100644
index 549c2e7..0000000
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryListener.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.imageshow;
-
-public interface GeometryListener {
- public void geometryChanged();
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java
deleted file mode 100644
index 568dadf..0000000
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java
+++ /dev/null
@@ -1,143 +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.Rect;
-import android.graphics.RectF;
-
-public class GeometryMath {
-
- // Math operations for 2d vectors
- public static float clamp(float i, float low, float high) {
- return Math.max(Math.min(i, high), low);
- }
-
- public static float[] lineIntersect(float[] line1, float[] line2) {
- float a0 = line1[0];
- float a1 = line1[1];
- float b0 = line1[2];
- float b1 = line1[3];
- float c0 = line2[0];
- float c1 = line2[1];
- float d0 = line2[2];
- float d1 = line2[3];
- float t0 = a0 - b0;
- float t1 = a1 - b1;
- float t2 = b0 - d0;
- float t3 = d1 - b1;
- float t4 = c0 - d0;
- float t5 = c1 - d1;
-
- float denom = t1 * t4 - t0 * t5;
- if (denom == 0)
- return null;
- float u = (t3 * t4 + t5 * t2) / denom;
- float[] intersect = {
- b0 + u * t0, b1 + u * t1
- };
- return intersect;
- }
-
- public static float[] shortestVectorFromPointToLine(float[] point, float[] line) {
- float x1 = line[0];
- float x2 = line[2];
- float y1 = line[1];
- float y2 = line[3];
- float xdelt = x2 - x1;
- float ydelt = y2 - y1;
- if (xdelt == 0 && ydelt == 0)
- return null;
- float u = ((point[0] - x1) * xdelt + (point[1] - y1) * ydelt)
- / (xdelt * xdelt + ydelt * ydelt);
- float[] ret = {
- (x1 + u * (x2 - x1)), (y1 + u * (y2 - y1))
- };
- float[] vec = {
- ret[0] - point[0], ret[1] - point[1]
- };
- return vec;
- }
-
- // A . B
- public static float dotProduct(float[] a, float[] b) {
- return a[0] * b[0] + a[1] * b[1];
- }
-
- public static float[] normalize(float[] a) {
- float length = (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]);
- float[] b = {
- a[0] / length, a[1] / length
- };
- return b;
- }
-
- // A onto B
- public static float scalarProjection(float[] a, float[] b) {
- float length = (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]);
- return dotProduct(a, b) / length;
- }
-
- public static float[] getVectorFromPoints(float[] point1, float[] point2) {
- float[] p = {
- point2[0] - point1[0], point2[1] - point1[1]
- };
- return p;
- }
-
- public static float[] getUnitVectorFromPoints(float[] point1, float[] point2) {
- float[] p = {
- point2[0] - point1[0], point2[1] - point1[1]
- };
- float length = (float) Math.sqrt(p[0] * p[0] + p[1] * p[1]);
- p[0] = p[0] / length;
- p[1] = p[1] / length;
- return p;
- }
-
- public static RectF scaleRect(RectF r, float scale) {
- return new RectF(r.left * scale, r.top * scale, r.right * scale, r.bottom * scale);
- }
-
- // A - B
- public static float[] vectorSubtract(float[] a, float[] b) {
- int len = a.length;
- if (len != b.length)
- return null;
- float[] ret = new float[len];
- for (int i = 0; i < len; i++) {
- ret[i] = a[i] - b[i];
- }
- return ret;
- }
-
- public static float vectorLength(float[] a) {
- return (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]);
- }
-
- public static float scale(float oldWidth, float oldHeight, float newWidth, float newHeight) {
- if (oldHeight == 0 || oldWidth == 0)
- return 1;
- return Math.min(newWidth / oldWidth, newHeight / oldHeight);
- }
-
- public static Rect roundNearest(RectF r) {
- Rect q = new Rect(Math.round(r.left), Math.round(r.top), Math.round(r.right),
- Math.round(r.bottom));
- return q;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java
new file mode 100644
index 0000000..81394f1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java
@@ -0,0 +1,416 @@
+/*
+ * 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.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation.Mirror;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation.Rotation;
+import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
+import com.android.gallery3d.filtershow.pipeline.ImagePreset;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+public final class GeometryMathUtils {
+ private GeometryMathUtils() {};
+
+ // Holder class for Geometry data.
+ public static final class GeometryHolder {
+ public Rotation rotation = FilterRotateRepresentation.getNil();
+ public float straighten = FilterStraightenRepresentation.getNil();
+ public RectF crop = FilterCropRepresentation.getNil();
+ public Mirror mirror = FilterMirrorRepresentation.getNil();
+
+ public void set(GeometryHolder h) {
+ rotation = h.rotation;
+ straighten = h.straighten;
+ crop.set(h.crop);
+ mirror = h.mirror;
+ }
+
+ public void wipe() {
+ rotation = FilterRotateRepresentation.getNil();
+ straighten = FilterStraightenRepresentation.getNil();
+ crop = FilterCropRepresentation.getNil();
+ mirror = FilterMirrorRepresentation.getNil();
+ }
+
+ public boolean isNil() {
+ return rotation == FilterRotateRepresentation.getNil() &&
+ straighten == FilterStraightenRepresentation.getNil() &&
+ crop.equals(FilterCropRepresentation.getNil()) &&
+ mirror == FilterMirrorRepresentation.getNil();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof GeometryHolder)) {
+ return false;
+ }
+ GeometryHolder h = (GeometryHolder) o;
+ return rotation == h.rotation && straighten == h.straighten &&
+ ((crop == null && h.crop == null) || (crop != null && crop.equals(h.crop))) &&
+ mirror == h.mirror;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + "rotation:" + rotation.value()
+ + ",straighten:" + straighten + ",crop:" + crop.toString()
+ + ",mirror:" + mirror.value() + "]";
+ }
+ }
+
+ // Math operations for 2d vectors
+ public static float clamp(float i, float low, float high) {
+ return Math.max(Math.min(i, high), low);
+ }
+
+ public static float[] lineIntersect(float[] line1, float[] line2) {
+ float a0 = line1[0];
+ float a1 = line1[1];
+ float b0 = line1[2];
+ float b1 = line1[3];
+ float c0 = line2[0];
+ float c1 = line2[1];
+ float d0 = line2[2];
+ float d1 = line2[3];
+ float t0 = a0 - b0;
+ float t1 = a1 - b1;
+ float t2 = b0 - d0;
+ float t3 = d1 - b1;
+ float t4 = c0 - d0;
+ float t5 = c1 - d1;
+
+ float denom = t1 * t4 - t0 * t5;
+ if (denom == 0)
+ return null;
+ float u = (t3 * t4 + t5 * t2) / denom;
+ float[] intersect = {
+ b0 + u * t0, b1 + u * t1
+ };
+ return intersect;
+ }
+
+ public static float[] shortestVectorFromPointToLine(float[] point, float[] line) {
+ float x1 = line[0];
+ float x2 = line[2];
+ float y1 = line[1];
+ float y2 = line[3];
+ float xdelt = x2 - x1;
+ float ydelt = y2 - y1;
+ if (xdelt == 0 && ydelt == 0)
+ return null;
+ float u = ((point[0] - x1) * xdelt + (point[1] - y1) * ydelt)
+ / (xdelt * xdelt + ydelt * ydelt);
+ float[] ret = {
+ (x1 + u * (x2 - x1)), (y1 + u * (y2 - y1))
+ };
+ float[] vec = {
+ ret[0] - point[0], ret[1] - point[1]
+ };
+ return vec;
+ }
+
+ // A . B
+ public static float dotProduct(float[] a, float[] b) {
+ return a[0] * b[0] + a[1] * b[1];
+ }
+
+ public static float[] normalize(float[] a) {
+ float length = (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]);
+ float[] b = {
+ a[0] / length, a[1] / length
+ };
+ return b;
+ }
+
+ // A onto B
+ public static float scalarProjection(float[] a, float[] b) {
+ float length = (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]);
+ return dotProduct(a, b) / length;
+ }
+
+ public static float[] getVectorFromPoints(float[] point1, float[] point2) {
+ float[] p = {
+ point2[0] - point1[0], point2[1] - point1[1]
+ };
+ return p;
+ }
+
+ public static float[] getUnitVectorFromPoints(float[] point1, float[] point2) {
+ float[] p = {
+ point2[0] - point1[0], point2[1] - point1[1]
+ };
+ float length = (float) Math.sqrt(p[0] * p[0] + p[1] * p[1]);
+ p[0] = p[0] / length;
+ p[1] = p[1] / length;
+ return p;
+ }
+
+ public static void scaleRect(RectF r, float scale) {
+ r.set(r.left * scale, r.top * scale, r.right * scale, r.bottom * scale);
+ }
+
+ // A - B
+ public static float[] vectorSubtract(float[] a, float[] b) {
+ int len = a.length;
+ if (len != b.length)
+ return null;
+ float[] ret = new float[len];
+ for (int i = 0; i < len; i++) {
+ ret[i] = a[i] - b[i];
+ }
+ return ret;
+ }
+
+ public static float vectorLength(float[] a) {
+ return (float) Math.sqrt(a[0] * a[0] + a[1] * a[1]);
+ }
+
+ public static float scale(float oldWidth, float oldHeight, float newWidth, float newHeight) {
+ if (oldHeight == 0 || oldWidth == 0 || (oldWidth == newWidth && oldHeight == newHeight)) {
+ return 1;
+ }
+ return Math.min(newWidth / oldWidth, newHeight / oldHeight);
+ }
+
+ public static Rect roundNearest(RectF r) {
+ Rect q = new Rect(Math.round(r.left), Math.round(r.top), Math.round(r.right),
+ Math.round(r.bottom));
+ return q;
+ }
+
+ private static void concatMirrorMatrix(Matrix m, Mirror type) {
+ if (type == Mirror.HORIZONTAL) {
+ m.postScale(-1, 1);
+ } else if (type == Mirror.VERTICAL) {
+ m.postScale(1, -1);
+ } else if (type == Mirror.BOTH) {
+ m.postScale(1, -1);
+ m.postScale(-1, 1);
+ }
+ }
+
+ private static int getRotationForOrientation(int orientation) {
+ switch (orientation) {
+ case ImageLoader.ORI_ROTATE_90:
+ return 90;
+ case ImageLoader.ORI_ROTATE_180:
+ return 180;
+ case ImageLoader.ORI_ROTATE_270:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+
+ public static GeometryHolder unpackGeometry(Collection<FilterRepresentation> geometry) {
+ GeometryHolder holder = new GeometryHolder();
+ unpackGeometry(holder, geometry);
+ return holder;
+ }
+
+ public static void unpackGeometry(GeometryHolder out,
+ Collection<FilterRepresentation> geometry) {
+ out.wipe();
+ // Get geometry data from filters
+ for (FilterRepresentation r : geometry) {
+ if (r.isNil()) {
+ continue;
+ }
+ if (r.getSerializationName() == FilterRotateRepresentation.SERIALIZATION_NAME) {
+ out.rotation = ((FilterRotateRepresentation) r).getRotation();
+ } else if (r.getSerializationName() ==
+ FilterStraightenRepresentation.SERIALIZATION_NAME) {
+ out.straighten = ((FilterStraightenRepresentation) r).getStraighten();
+ } else if (r.getSerializationName() == FilterCropRepresentation.SERIALIZATION_NAME) {
+ ((FilterCropRepresentation) r).getCrop(out.crop);
+ } else if (r.getSerializationName() == FilterMirrorRepresentation.SERIALIZATION_NAME) {
+ out.mirror = ((FilterMirrorRepresentation) r).getMirror();
+ }
+ }
+ }
+
+ public static void replaceInstances(Collection<FilterRepresentation> geometry,
+ FilterRepresentation rep) {
+ Iterator<FilterRepresentation> iter = geometry.iterator();
+ while (iter.hasNext()) {
+ FilterRepresentation r = iter.next();
+ if (ImagePreset.sameSerializationName(rep, r)) {
+ iter.remove();
+ }
+ }
+ if (!rep.isNil()) {
+ geometry.add(rep);
+ }
+ }
+
+ public static void initializeHolder(GeometryHolder outHolder,
+ FilterRepresentation currentLocal) {
+ Collection<FilterRepresentation> geometry = MasterImage.getImage().getPreset()
+ .getGeometryFilters();
+ replaceInstances(geometry, currentLocal);
+ unpackGeometry(outHolder, geometry);
+ }
+
+ private static Bitmap applyFullGeometryMatrix(Bitmap image, GeometryHolder holder) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ RectF crop = getTrueCropRect(holder, width, height);
+ Rect frame = new Rect();
+ crop.roundOut(frame);
+ Matrix m = getCropSelectionToScreenMatrix(null, holder, width, height, frame.width(),
+ frame.height());
+ Bitmap temp = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(temp);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setFilterBitmap(true);
+ paint.setDither(true);
+ canvas.drawBitmap(image, m, paint);
+ return temp;
+ }
+
+ public static Matrix getImageToScreenMatrix(Collection<FilterRepresentation> geometry,
+ boolean reflectRotation, Rect bmapDimens, float viewWidth, float viewHeight) {
+ GeometryHolder h = unpackGeometry(geometry);
+ return GeometryMathUtils.getOriginalToScreen(h, reflectRotation, bmapDimens.width(),
+ bmapDimens.height(), viewWidth, viewHeight);
+ }
+
+ public static Matrix getOriginalToScreen(GeometryHolder holder, boolean rotate,
+ float originalWidth,
+ float originalHeight, float viewWidth, float viewHeight) {
+ int orientation = MasterImage.getImage().getZoomOrientation();
+ int rotation = getRotationForOrientation(orientation);
+ Rotation prev = holder.rotation;
+ rotation = (rotation + prev.value()) % 360;
+ holder.rotation = Rotation.fromValue(rotation);
+ Matrix m = getCropSelectionToScreenMatrix(null, holder, (int) originalWidth,
+ (int) originalHeight, (int) viewWidth, (int) viewHeight);
+ holder.rotation = prev;
+ return m;
+ }
+
+ public static Bitmap applyGeometryRepresentations(Collection<FilterRepresentation> res,
+ Bitmap image) {
+ GeometryHolder holder = unpackGeometry(res);
+ Bitmap bmap = image;
+ // If there are geometry changes, apply them to the image
+ if (!holder.isNil()) {
+ bmap = applyFullGeometryMatrix(bmap, holder);
+ }
+ return bmap;
+ }
+
+ public static RectF drawTransformedCropped(GeometryHolder holder, Canvas canvas,
+ Bitmap photo, int viewWidth, int viewHeight) {
+ if (photo == null) {
+ return null;
+ }
+ RectF crop = new RectF();
+ Matrix m = getCropSelectionToScreenMatrix(crop, holder, photo.getWidth(), photo.getHeight(),
+ viewWidth, viewHeight);
+ canvas.save();
+ canvas.clipRect(crop);
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ canvas.drawBitmap(photo, m, p);
+ canvas.restore();
+ return crop;
+ }
+
+ public static boolean needsDimensionSwap(Rotation rotation) {
+ switch (rotation) {
+ case NINETY:
+ case TWO_SEVENTY:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // Gives matrix for rotated, straightened, mirrored bitmap centered at 0,0.
+ private static Matrix getFullGeometryMatrix(GeometryHolder holder, int bitmapWidth,
+ int bitmapHeight) {
+ float centerX = bitmapWidth / 2f;
+ float centerY = bitmapHeight / 2f;
+ Matrix m = new Matrix();
+ m.setTranslate(-centerX, -centerY);
+ m.postRotate(holder.straighten + holder.rotation.value());
+ concatMirrorMatrix(m, holder.mirror);
+ return m;
+ }
+
+ public static Matrix getFullGeometryToScreenMatrix(GeometryHolder holder, int bitmapWidth,
+ int bitmapHeight, int viewWidth, int viewHeight) {
+ float scale = GeometryMathUtils.scale(bitmapWidth, bitmapHeight, viewWidth, viewHeight);
+ Matrix m = getFullGeometryMatrix(holder, bitmapWidth, bitmapHeight);
+ m.postScale(scale, scale);
+ m.postTranslate(viewWidth / 2f, viewHeight / 2f);
+ return m;
+ }
+
+ public static RectF getTrueCropRect(GeometryHolder holder, int bitmapWidth, int bitmapHeight) {
+ RectF r = new RectF(holder.crop);
+ FilterCropRepresentation.findScaledCrop(r, bitmapWidth, bitmapHeight);
+ float s = holder.straighten;
+ holder.straighten = 0;
+ Matrix m1 = getFullGeometryMatrix(holder, bitmapWidth, bitmapHeight);
+ holder.straighten = s;
+ m1.mapRect(r);
+ return r;
+ }
+
+ public static Matrix getCropSelectionToScreenMatrix(RectF outCrop, GeometryHolder holder,
+ int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) {
+ Matrix m = getFullGeometryMatrix(holder, bitmapWidth, bitmapHeight);
+ RectF crop = getTrueCropRect(holder, bitmapWidth, bitmapHeight);
+ float scale = GeometryMathUtils.scale(crop.width(), crop.height(), viewWidth, viewHeight);
+ m.postScale(scale, scale);
+ GeometryMathUtils.scaleRect(crop, scale);
+ m.postTranslate(viewWidth / 2f - crop.centerX(), viewHeight / 2f - crop.centerY());
+ if (outCrop != null) {
+ crop.offset(viewWidth / 2f - crop.centerX(), viewHeight / 2f - crop.centerY());
+ outCrop.set(crop);
+ }
+ return m;
+ }
+
+ public static Matrix getCropSelectionToScreenMatrix(RectF outCrop,
+ Collection<FilterRepresentation> res, int bitmapWidth, int bitmapHeight, int viewWidth,
+ int viewHeight) {
+ GeometryHolder holder = unpackGeometry(res);
+ return getCropSelectionToScreenMatrix(outCrop, holder, bitmapWidth, bitmapHeight,
+ viewWidth, viewHeight);
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
deleted file mode 100644
index adfce85..0000000
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
+++ /dev/null
@@ -1,490 +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.Bitmap;
-import android.graphics.Matrix;
-import android.graphics.RectF;
-import android.util.JsonReader;
-import android.util.JsonWriter;
-
-import com.android.gallery3d.filtershow.cache.ImageLoader;
-import com.android.gallery3d.filtershow.editors.EditorCrop;
-import com.android.gallery3d.filtershow.editors.EditorFlip;
-import com.android.gallery3d.filtershow.editors.EditorRotate;
-import com.android.gallery3d.filtershow.editors.EditorStraighten;
-import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
-import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
-import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation.Mirror;
-import com.android.gallery3d.filtershow.filters.FilterRepresentation;
-import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
-import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation.Rotation;
-import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
-import com.android.gallery3d.filtershow.filters.ImageFilterGeometry;
-
-import java.util.HashMap;
-import java.io.IOException;
-
-public class GeometryMetadata extends FilterRepresentation {
- public static final String SERIALIZATION_NAME = "GEOM";
- public static final String SERIALIZATION_VALUE_SCALE = "scalevalue";
- private static final String LOGTAG = "GeometryMetadata";
- private float mScaleFactor = 1.0f;
-
- private FilterRotateRepresentation mRotationRep = new FilterRotateRepresentation();
- private FilterStraightenRepresentation mStraightenRep = new FilterStraightenRepresentation();
- private FilterCropRepresentation mCropRep = new FilterCropRepresentation();
- private FilterMirrorRepresentation mMirrorRep = new FilterMirrorRepresentation();
-
- public GeometryMetadata() {
- super("GeometryMetadata");
- setSerializationName(SERIALIZATION_NAME);
- setFilterClass(ImageFilterGeometry.class);
- setEditorId(EditorCrop.ID);
- setTextId(0);
- setShowParameterValue(true);
- }
-
- @Override
- public int[] getEditorIds() {
- return new int[] {
- EditorCrop.ID,
- EditorStraighten.ID,
- EditorRotate.ID,
- EditorFlip.ID
- };
- }
-
- public GeometryMetadata(GeometryMetadata g) {
- super("GeometryMetadata");
- set(g);
- }
-
- public boolean hasModifications() {
- if (mScaleFactor != 1.0f) {
- return true;
- }
- if (!mRotationRep.isNil()) {
- return true;
- }
- if (!mStraightenRep.isNil()) {
- return true;
- }
- if (!mCropRep.isNil()) {
- return true;
- }
- if (!mMirrorRep.isNil()) {
- return true;
- }
- return false;
- }
-
- public void set(GeometryMetadata g) {
- mScaleFactor = g.mScaleFactor;
- mRotationRep.set(g.mRotationRep);
- mStraightenRep.set(g.mStraightenRep);
- mCropRep.set(g.mCropRep);
- mMirrorRep.set(g.mMirrorRep);
- }
-
- @Override
- public boolean equals(FilterRepresentation rep) {
- if (!(rep instanceof GeometryMetadata)) {
- return false;
- }
- GeometryMetadata geo = (GeometryMetadata) rep;
- if (geo.mScaleFactor != mScaleFactor
- || !geo.mRotationRep.equals(mRotationRep)
- || !geo.mStraightenRep.equals(mStraightenRep)
- || !geo.mCropRep.equals(mCropRep)
- || !geo.mMirrorRep.equals(mMirrorRep)) {
- return false;
- }
- return true;
- }
-
- public float getScaleFactor() {
- return mScaleFactor;
- }
-
- public int getRotation() {
- return mRotationRep.getRotation().value();
- }
-
- public float getStraightenRotation() {
- return mStraightenRep.getStraighten();
- }
-
- public RectF getPreviewCropBounds() {
- return mCropRep.getCrop();
- }
-
- public RectF getCropBounds(Bitmap bitmap) {
- float scale = 1.0f;
- RectF photoBounds = mCropRep.getImage();
- RectF cropBounds = mCropRep.getCrop();
- scale = GeometryMath.scale(photoBounds.width(), photoBounds.height(), bitmap.getWidth(),
- bitmap.getHeight());
- RectF croppedRegion = new RectF(cropBounds.left * scale, cropBounds.top * scale,
- cropBounds.right * scale, cropBounds.bottom * scale);
-
- // If no crop has been applied, make sure to use the exact size values.
- // Multiplying using scale will introduce rounding errors that modify
- // even un-cropped images.
- if (cropBounds.left == 0 && cropBounds.right == photoBounds.right) {
- croppedRegion.left = 0;
- croppedRegion.right = bitmap.getWidth();
- }
- if (cropBounds.top == 0 && cropBounds.bottom == photoBounds.bottom) {
- croppedRegion.top = 0;
- croppedRegion.bottom = bitmap.getHeight();
- }
- return croppedRegion;
- }
-
- public Mirror getMirrorType() {
- return mMirrorRep.getMirror();
- }
-
- public void setMirrorType(Mirror m) {
- mMirrorRep.setMirror(m);
- }
-
- public RectF getPhotoBounds() {
- return mCropRep.getImage();
- }
-
- public void setScaleFactor(float scale) {
- mScaleFactor = scale;
- }
-
- public void setRotation(int rotation) {
- Rotation r = Rotation.fromValue(rotation % 360);
- mRotationRep.setRotation((r == null) ? Rotation.ZERO : r);
- }
-
- public void setStraightenRotation(float straighten) {
- mStraightenRep.setStraighten(straighten);
- }
-
- public void setCropBounds(RectF newCropBounds) {
- mCropRep.setCrop(newCropBounds);
- }
-
- public void setPhotoBounds(RectF newPhotoBounds) {
- mCropRep.setImage(newPhotoBounds);
- }
-
- protected static void concatHorizontalMatrix(Matrix m, float width) {
- m.postScale(-1, 1);
- m.postTranslate(width, 0);
- }
-
- protected static void concatVerticalMatrix(Matrix m, float height) {
- m.postScale(1, -1);
- m.postTranslate(0, height);
- }
-
- public static void concatMirrorMatrix(Matrix m, float width, float height, Mirror type) {
- if (type == Mirror.HORIZONTAL) {
- concatHorizontalMatrix(m, width);
- } else if (type == Mirror.VERTICAL) {
- concatVerticalMatrix(m, height);
- } else if (type == Mirror.BOTH) {
- concatVerticalMatrix(m, height);
- concatHorizontalMatrix(m, width);
- }
- }
-
- public static Matrix getMatrixOriginalOrientation(int orientation, float originalWidth,
- float originalHeight) {
- Matrix imageRotation = new Matrix();
- switch (orientation) {
- case ImageLoader.ORI_ROTATE_90: {
- imageRotation.setRotate(90, originalWidth / 2f, originalHeight / 2f);
- imageRotation.postTranslate(-(originalWidth - originalHeight) / 2f,
- -(originalHeight - originalWidth) / 2f);
- break;
- }
- case ImageLoader.ORI_ROTATE_180: {
- imageRotation.setRotate(180, originalWidth / 2f, originalHeight / 2f);
- break;
- }
- case ImageLoader.ORI_ROTATE_270: {
- imageRotation.setRotate(270, originalWidth / 2f, originalHeight / 2f);
- imageRotation.postTranslate(-(originalWidth - originalHeight) / 2f,
- -(originalHeight - originalWidth) / 2f);
- break;
- }
- case ImageLoader.ORI_FLIP_HOR: {
- imageRotation.preScale(-1, 1);
- break;
- }
- case ImageLoader.ORI_FLIP_VERT: {
- imageRotation.preScale(1, -1);
- break;
- }
- case ImageLoader.ORI_TRANSPOSE: {
- imageRotation.setRotate(90, originalWidth / 2f, originalHeight / 2f);
- imageRotation.postTranslate(-(originalWidth - originalHeight) / 2f,
- -(originalHeight - originalWidth) / 2f);
- imageRotation.preScale(1, -1);
- break;
- }
- case ImageLoader.ORI_TRANSVERSE: {
- imageRotation.setRotate(270, originalWidth / 2f, originalHeight / 2f);
- imageRotation.postTranslate(-(originalWidth - originalHeight) / 2f,
- -(originalHeight - originalWidth) / 2f);
- imageRotation.preScale(1, -1);
- break;
- }
- }
- return imageRotation;
- }
-
- public Matrix getOriginalToScreen(boolean rotate, float originalWidth, float originalHeight,
- float viewWidth, float viewHeight) {
- RectF photoBounds = getPhotoBounds();
- RectF cropBounds = getPreviewCropBounds();
- float imageWidth = cropBounds.width();
- float imageHeight = cropBounds.height();
-
- int orientation = MasterImage.getImage().getZoomOrientation();
- Matrix imageRotation = getMatrixOriginalOrientation(orientation, originalWidth,
- originalHeight);
- if (orientation == ImageLoader.ORI_ROTATE_90 ||
- orientation == ImageLoader.ORI_ROTATE_270 ||
- orientation == ImageLoader.ORI_TRANSPOSE ||
- orientation == ImageLoader.ORI_TRANSVERSE) {
- float tmp = originalWidth;
- originalWidth = originalHeight;
- originalHeight = tmp;
- }
-
- float preScale = GeometryMath.scale(originalWidth, originalHeight,
- photoBounds.width(), photoBounds.height());
- float scale = GeometryMath.scale(imageWidth, imageHeight, viewWidth, viewHeight);
- // checks if local rotation is an odd multiple of 90.
- if (((int) (getRotation() / 90)) % 2 != 0) {
- scale = GeometryMath.scale(imageWidth, imageHeight, viewHeight, viewWidth);
- }
- // put in screen coordinates
- RectF scaledCrop = GeometryMath.scaleRect(cropBounds, scale);
- RectF scaledPhoto = GeometryMath.scaleRect(photoBounds, scale);
- float[] displayCenter = {
- viewWidth / 2f, viewHeight / 2f
- };
- Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop,
- getRotation(), getStraightenRotation(), getMirrorType(), displayCenter);
- float[] cropCenter = {
- scaledCrop.centerX(), scaledCrop.centerY()
- };
- m1.mapPoints(cropCenter);
- GeometryMetadata.concatRecenterMatrix(m1, cropCenter, displayCenter);
- m1.preRotate(getStraightenRotation(), scaledPhoto.centerX(), scaledPhoto.centerY());
- m1.preScale(scale, scale);
- m1.preScale(preScale, preScale);
- m1.preConcat(imageRotation);
-
- return m1;
- }
-
- public boolean hasSwitchedWidthHeight() {
- return (((int) (mRotationRep.getRotation().value() / 90)) % 2) != 0;
- }
-
- public static Matrix buildPhotoMatrix(RectF photo, RectF crop, float rotation,
- float straighten, Mirror type) {
- Matrix m = new Matrix();
- m.setRotate(straighten, photo.centerX(), photo.centerY());
- concatMirrorMatrix(m, photo.right, photo.bottom, type);
- m.postRotate(rotation, crop.centerX(), crop.centerY());
-
- return m;
- }
-
- public static Matrix buildCropMatrix(RectF crop, float rotation) {
- Matrix m = new Matrix();
- m.setRotate(rotation, crop.centerX(), crop.centerY());
- return m;
- }
-
- public static void concatRecenterMatrix(Matrix m, float[] currentCenter, float[] newCenter) {
- m.postTranslate(newCenter[0] - currentCenter[0], newCenter[1] - currentCenter[1]);
- }
-
- /**
- * Builds a matrix to transform a bitmap of width bmWidth and height
- * bmHeight so that the region of the bitmap being cropped to is oriented
- * and centered at displayCenter.
- *
- * @param bmWidth
- * @param bmHeight
- * @param displayCenter
- * @return
- */
- public Matrix buildTotalXform(float bmWidth, float bmHeight, float[] displayCenter) {
- RectF rp = getPhotoBounds();
- RectF rc = getPreviewCropBounds();
- float scale = GeometryMath.scale(rp.width(), rp.height(), bmWidth, bmHeight);
- RectF scaledCrop = GeometryMath.scaleRect(rc, scale);
- RectF scaledPhoto = GeometryMath.scaleRect(rp, scale);
-
- // If no crop has been applied, make sure to use the exact size values.
- // Multiplying using scale will introduce rounding errors that modify
- // even un-cropped images.
- if (rc.left == 0 && rc.right == rp.right) {
- scaledCrop.left = scaledPhoto.left = 0;
- scaledCrop.right = scaledPhoto.right = bmWidth;
- }
- if (rc.top == 0 && rc.bottom == rp.bottom) {
- scaledCrop.top = scaledPhoto.top = 0;
- scaledCrop.bottom = scaledPhoto.bottom = bmHeight;
- }
-
- Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop,
- getRotation(), getStraightenRotation(),
- getMirrorType(), displayCenter);
- float[] cropCenter = {
- scaledCrop.centerX(), scaledCrop.centerY()
- };
- m1.mapPoints(cropCenter);
-
- GeometryMetadata.concatRecenterMatrix(m1, cropCenter, displayCenter);
- m1.preRotate(getStraightenRotation(), scaledPhoto.centerX(),
- scaledPhoto.centerY());
- return m1;
- }
-
- /**
- * Builds a matrix that rotates photo rect about it's center by the
- * straighten angle, mirrors it about the crop center, and rotates it about
- * the crop center by the rotation angle, and re-centers the photo rect.
- *
- * @param photo
- * @param crop
- * @param rotation
- * @param straighten
- * @param type
- * @param newCenter
- * @return
- */
- public static Matrix buildCenteredPhotoMatrix(RectF photo, RectF crop, float rotation,
- float straighten, Mirror type, float[] newCenter) {
- Matrix m = buildPhotoMatrix(photo, crop, rotation, straighten, type);
- float[] center = {
- photo.centerX(), photo.centerY()
- };
- m.mapPoints(center);
- concatRecenterMatrix(m, center, newCenter);
- return m;
- }
-
- /**
- * Builds a matrix that rotates a crop rect about it's center by rotation
- * angle, then re-centers the crop rect.
- *
- * @param crop
- * @param rotation
- * @param newCenter
- * @return
- */
- public static Matrix buildCenteredCropMatrix(RectF crop, float rotation, float[] newCenter) {
- Matrix m = buildCropMatrix(crop, rotation);
- float[] center = {
- crop.centerX(), crop.centerY()
- };
- m.mapPoints(center);
- concatRecenterMatrix(m, center, newCenter);
- return m;
- }
-
- /**
- * Builds a matrix that transforms the crop rect to its view coordinates
- * inside the photo rect.
- *
- * @param photo
- * @param crop
- * @param rotation
- * @param straighten
- * @param type
- * @param newCenter
- * @return
- */
- public static Matrix buildWanderingCropMatrix(RectF photo, RectF crop, float rotation,
- float straighten, Mirror type, float[] newCenter) {
- Matrix m = buildCenteredPhotoMatrix(photo, crop, rotation, straighten, type, newCenter);
- m.preRotate(-straighten, photo.centerX(), photo.centerY());
- return m;
- }
-
- @Override
- public void useParametersFrom(FilterRepresentation a) {
- GeometryMetadata data = (GeometryMetadata) a;
- set(data);
- }
-
- @Override
- public FilterRepresentation copy() {
- GeometryMetadata representation = new GeometryMetadata();
- copyAllParameters(representation);
- return representation;
- }
-
- @Override
- protected void copyAllParameters(FilterRepresentation representation) {
- super.copyAllParameters(representation);
- representation.useParametersFrom(this);
- }
-
- @Override
- public void serializeRepresentation(JsonWriter writer) throws IOException {
- writer.beginObject();
- writer.name(FilterRotateRepresentation.SERIALIZATION_NAME);
- mRotationRep.serializeRepresentation(writer);
- writer.name(FilterMirrorRepresentation.SERIALIZATION_NAME);
- mMirrorRep.serializeRepresentation(writer);
- writer.name(FilterStraightenRepresentation.SERIALIZATION_NAME);
- mStraightenRep.serializeRepresentation(writer);
- writer.name(FilterCropRepresentation.SERIALIZATION_NAME);
- mCropRep.serializeRepresentation(writer);
- writer.name(SERIALIZATION_VALUE_SCALE).value(mScaleFactor);
- writer.endObject();
- }
-
- @Override
- public void deSerializeRepresentation(JsonReader reader) throws IOException {
- reader.beginObject();
- while (reader.hasNext()) {
- String name = reader.nextName();
- if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) {
- mRotationRep.deSerializeRepresentation(reader);
- } else if (FilterMirrorRepresentation.SERIALIZATION_NAME.equals(name)) {
- mMirrorRep.deSerializeRepresentation(reader);
- } else if (FilterStraightenRepresentation.SERIALIZATION_NAME.equals(name)) {
- mStraightenRep.deSerializeRepresentation(reader);
- } else if (FilterCropRepresentation.SERIALIZATION_NAME.equals(name)) {
- mCropRep.deSerializeRepresentation(reader);
- } else if (SERIALIZATION_VALUE_SCALE.equals(name)) {
- mScaleFactor = (float) reader.nextDouble();
- } else {
- reader.skipValue();
- }
- }
- reader.endObject();
- }
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
index 0c44065..7fee031 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -20,712 +20,288 @@ 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.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.PopupMenu;
+import android.util.Log;
+import android.view.MotionEvent;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.crop.BoundedRect;
-import com.android.gallery3d.filtershow.crop.CropExtras;
+import com.android.gallery3d.filtershow.crop.CropDrawingUtils;
import com.android.gallery3d.filtershow.crop.CropMath;
+import com.android.gallery3d.filtershow.crop.CropObject;
import com.android.gallery3d.filtershow.editors.EditorCrop;
-import com.android.gallery3d.filtershow.ui.FramedTextButton;
-
-public class ImageCrop extends ImageGeometry {
- private static final boolean LOGV = false;
-
- // Sides
- private static final int MOVE_LEFT = 1;
- private static final int MOVE_TOP = 2;
- private static final int MOVE_RIGHT = 4;
- private static final int MOVE_BOTTOM = 8;
- private static final int MOVE_BLOCK = 16;
-
- // Corners
- private static final int TOP_LEFT = MOVE_TOP | MOVE_LEFT;
- private static final int TOP_RIGHT = MOVE_TOP | MOVE_RIGHT;
- private static final int BOTTOM_RIGHT = MOVE_BOTTOM | MOVE_RIGHT;
- private static final int BOTTOM_LEFT = MOVE_BOTTOM | MOVE_LEFT;
-
- private static int mMinSideSize = 100;
- private static int mTouchTolerance = 45;
-
- private boolean mFirstDraw = true;
- private float mAspectWidth = 1;
- private float mAspectHeight = 1;
- private boolean mFixAspectRatio = false;
-
- private float mLastRot = 0;
-
- private BoundedRect mBounded = null;
- private int movingEdges;
- private final Drawable cropIndicator;
- private final int indicatorSize;
- private final int mBorderColor = Color.argb(128, 255, 255, 255);
-
- // Offset between crop center and photo center
- private float[] mOffset = {
- 0, 0
- };
- private CropExtras mCropExtras = null;
- private boolean mDoingCropIntentAction = false;
-
- private static final String LOGTAG = "ImageCrop";
-
- private String mAspect = "";
- private static int mAspectTextSize = 24;
-
- private boolean mFixedAspect = false;
-
- private EditorCrop mEditorCrop;
-
- public static void setAspectTextSize(int textSize) {
- mAspectTextSize = textSize;
- }
-
- public void setAspectString(String a) {
- mAspect = a;
- }
-
- private static final Paint gPaint = new Paint();
+import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
+
+public class ImageCrop extends ImageShow {
+ private static final String TAG = ImageCrop.class.getSimpleName();
+ private RectF mImageBounds = new RectF();
+ private RectF mScreenCropBounds = new RectF();
+ private Paint mPaint = new Paint();
+ private CropObject mCropObj = null;
+ private GeometryHolder mGeometry = new GeometryHolder();
+ private GeometryHolder mUpdateHolder = new GeometryHolder();
+ private Drawable mCropIndicator;
+ private int mIndicatorSize;
+ private boolean mMovingBlock = false;
+ private Matrix mDisplayMatrix = null;
+ private Matrix mDisplayCropMatrix = null;
+ private Matrix mDisplayMatrixInverse = null;
+ private float mPrevX = 0;
+ private float mPrevY = 0;
+ private int mMinSideSize = 90;
+ private int mTouchTolerance = 40;
+ private enum Mode {
+ NONE, MOVE
+ }
+ private Mode mState = Mode.NONE;
+ private boolean mValidDraw = false;
+ FilterCropRepresentation mLocalRep = new FilterCropRepresentation();
+ EditorCrop mEditorCrop;
public ImageCrop(Context context) {
super(context);
- Resources resources = context.getResources();
- cropIndicator = resources.getDrawable(R.drawable.camera_crop);
- indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
+ setup(context);
}
public ImageCrop(Context context, AttributeSet attrs) {
super(context, attrs);
- Resources resources = context.getResources();
- cropIndicator = resources.getDrawable(R.drawable.camera_crop);
- indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
+ setup(context);
}
- private void swapAspect() {
- if (mDoingCropIntentAction) {
- return;
- }
- float temp = mAspectWidth;
- mAspectWidth = mAspectHeight;
- mAspectHeight = temp;
+ public ImageCrop(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setup(context);
}
- /**
- * Set tolerance for crop marker selection (in pixels)
- */
- public static void setTouchTolerance(int tolerance) {
- mTouchTolerance = tolerance;
+ private void setup(Context context) {
+ Resources rsc = context.getResources();
+ mCropIndicator = rsc.getDrawable(R.drawable.camera_crop);
+ mIndicatorSize = (int) rsc.getDimension(R.dimen.crop_indicator_size);
+ mMinSideSize = (int) rsc.getDimension(R.dimen.crop_min_side);
+ mTouchTolerance = (int) rsc.getDimension(R.dimen.crop_touch_tolerance);
}
- /**
- * Set minimum side length for crop box (in pixels)
- */
- public static void setMinCropSize(int minHeightWidth) {
- mMinSideSize = minHeightWidth;
+ public void setFilterCropRepresentation(FilterCropRepresentation crop) {
+ mLocalRep = (crop == null) ? new FilterCropRepresentation() : crop;
+ GeometryMathUtils.initializeHolder(mUpdateHolder, mLocalRep);
+ mValidDraw = true;
}
- public void setExtras(CropExtras e) {
- mCropExtras = e;
+ public FilterCropRepresentation getFinalRepresentation() {
+ return mLocalRep;
}
- public void setCropActionFlag(boolean f) {
- mDoingCropIntentAction = f;
+ private void internallyUpdateLocalRep(RectF crop, RectF image) {
+ FilterCropRepresentation
+ .findNormalizedCrop(crop, (int) image.width(), (int) image.height());
+ mGeometry.crop.set(crop);
+ mUpdateHolder.set(mGeometry);
+ mLocalRep.setCrop(crop);
}
- public void apply(float w, float h) {
- mFixAspectRatio = true;
- mAspectWidth = w;
- mAspectHeight = h;
- setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
- getLocalStraighten()));
- cropSetup();
- saveAndSetPreset();
+ @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;
+ }
+ break;
+ case (MotionEvent.ACTION_UP):
+ if (mState == Mode.MOVE) {
+ mCropObj.selectEdge(CropObject.MOVE_NONE);
+ mMovingBlock = false;
+ mPrevX = x;
+ mPrevY = y;
+ mState = Mode.NONE;
+ internallyUpdateLocalRep(mCropObj.getInnerBounds(), mCropObj.getOuterBounds());
+ }
+ 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;
+ }
+ break;
+ default:
+ break;
+ }
invalidate();
+ return true;
}
- public void applyOriginal() {
- mFixAspectRatio = true;
- RectF photobounds = getLocalPhotoBounds();
- float w = photobounds.width();
- float h = photobounds.height();
- float scale = Math.min(w, h);
- mAspectWidth = w / scale;
- mAspectHeight = h / scale;
- setLocalCropBounds(getUntranslatedStraightenCropBounds(photobounds,
- getLocalStraighten()));
- cropSetup();
- saveAndSetPreset();
+ private void clearDisplay() {
+ mDisplayMatrix = null;
+ mDisplayMatrixInverse = null;
invalidate();
}
- public void applyClear() {
- mFixAspectRatio = false;
- mAspectWidth = 1;
- mAspectHeight = 1;
- setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
- getLocalStraighten()));
- cropSetup();
- saveAndSetPreset();
+ public void applyFreeAspect() {
+ mCropObj.unsetAspectRatio();
invalidate();
}
- public void clear() {
- if (mCropExtras != null) {
- int x = mCropExtras.getAspectX();
- int y = mCropExtras.getAspectY();
- if (mDoingCropIntentAction && x > 0 && y > 0) {
- apply(x, y);
- }
+ public void applyOriginalAspect() {
+ RectF outer = mCropObj.getOuterBounds();
+ float w = outer.width();
+ float h = outer.height();
+ if (w > 0 && h > 0) {
+ applyAspect(w, h);
+ mCropObj.resetBoundsTo(outer, outer);
+ internallyUpdateLocalRep(mCropObj.getInnerBounds(), mCropObj.getOuterBounds());
} else {
- applyClear();
+ Log.w(TAG, "failed to set aspect ratio original");
}
- }
-
- private Matrix getPhotoBoundDisplayedMatrix() {
- float[] displayCenter = new float[2];
- RectF scaledCrop = new RectF();
- RectF scaledPhoto = new RectF();
- float scale = getTransformState(scaledPhoto, scaledCrop, displayCenter);
- Matrix m = GeometryMetadata.buildCenteredPhotoMatrix(scaledPhoto, scaledCrop,
- getLocalRotation(), getLocalStraighten(), getLocalMirror(), displayCenter);
- m.preScale(scale, scale);
- return m;
- }
-
- private Matrix getCropBoundDisplayedMatrix() {
- float[] displayCenter = new float[2];
- RectF scaledCrop = new RectF();
- RectF scaledPhoto = new RectF();
- float scale = getTransformState(scaledPhoto, scaledCrop, displayCenter);
- Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop,
- getLocalRotation(), getLocalStraighten(), getLocalMirror(), displayCenter);
- m1.preScale(scale, scale);
- return m1;
- }
-
- /**
- * Takes the rotated corners of a rectangle and returns the angle; sets
- * unrotated to be the unrotated version of the rectangle.
- */
- 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(CropMath.trapToRect(unrotatedRect));
- return angle;
- }
-
- /**
- * Sets cropped bounds; modifies the bounds if it's smaller than the allowed
- * dimensions.
- */
- public boolean setCropBounds(RectF bounds) {
- RectF cbounds = new RectF(bounds);
- Matrix mc = getCropBoundDisplayedMatrix();
- Matrix mcInv = new Matrix();
- mc.invert(mcInv);
- mcInv.mapRect(cbounds);
- // Avoid cropping smaller than minimum
- float newWidth = cbounds.width();
- float newHeight = cbounds.height();
- float scale = getTransformState(null, null, null);
- float minWidthHeight = mMinSideSize / scale;
- RectF pbounds = getLocalPhotoBounds();
-
- // if photo is smaller than minimum, refuse to set crop bounds
- if (pbounds.width() < minWidthHeight || pbounds.height() < minWidthHeight) {
- return false;
- }
-
- // if incoming crop is smaller than minimum, refuse to set crop bounds
- if (newWidth < minWidthHeight || newHeight < minWidthHeight) {
- return false;
- }
-
- float newX = bounds.centerX() - (getWidth() / 2f);
- float newY = bounds.centerY() - (getHeight() / 2f);
- mOffset[0] = newX;
- mOffset[1] = newY;
-
- setLocalCropBounds(cbounds);
invalidate();
- return true;
- }
-
- private BoundedRect getBoundedCrop(RectF crop) {
- RectF photo = getLocalPhotoBounds();
- Matrix mp = getPhotoBoundDisplayedMatrix();
- float[] photoCorners = CropMath.getCornersFromRect(photo);
- float[] photoCenter = {
- photo.centerX(), photo.centerY()
- };
- mp.mapPoints(photoCorners);
- mp.mapPoints(photoCenter);
- RectF scaledPhoto = new RectF();
- float angle = getUnrotated(photoCorners, photoCenter, scaledPhoto);
- return new BoundedRect(angle, scaledPhoto, crop);
}
- private void detectMovingEdges(float x, float y) {
- Matrix m = getCropBoundDisplayedMatrix();
- RectF cropped = getLocalCropBounds();
- m.mapRect(cropped);
- mBounded = getBoundedCrop(cropped);
- movingEdges = 0;
-
- float left = Math.abs(x - cropped.left);
- float right = Math.abs(x - cropped.right);
- float top = Math.abs(y - cropped.top);
- float bottom = Math.abs(y - cropped.bottom);
-
- // Check left or right.
- if ((left <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
- && ((y - mTouchTolerance) <= cropped.bottom) && (left < right)) {
- movingEdges |= MOVE_LEFT;
- }
- else if ((right <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
- && ((y - mTouchTolerance) <= cropped.bottom)) {
- movingEdges |= MOVE_RIGHT;
- }
-
- // Check top or bottom.
- if ((top <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
- && ((x - mTouchTolerance) <= cropped.right) && (top < bottom)) {
- movingEdges |= MOVE_TOP;
- }
- else if ((bottom <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
- && ((x - mTouchTolerance) <= cropped.right)) {
- movingEdges |= MOVE_BOTTOM;
+ public void applyAspect(float x, float y) {
+ if (x <= 0 || y <= 0) {
+ throw new IllegalArgumentException("Bad arguments to applyAspect");
}
- if (movingEdges == 0) {
- movingEdges = MOVE_BLOCK;
+ // If we are rotated by 90 degrees from horizontal, swap x and y
+ if (GeometryMathUtils.needsDimensionSwap(mGeometry.rotation)) {
+ float tmp = x;
+ x = y;
+ y = tmp;
}
- if (mFixAspectRatio && (movingEdges != MOVE_BLOCK)) {
- movingEdges = fixEdgeToCorner(movingEdges);
+ if (!mCropObj.setInnerAspectRatio(x, y)) {
+ Log.w(TAG, "failed to set aspect ratio");
}
+ internallyUpdateLocalRep(mCropObj.getInnerBounds(), mCropObj.getOuterBounds());
invalidate();
}
- private int fixEdgeToCorner(int moving_edges) {
- if (moving_edges == MOVE_LEFT) {
- moving_edges |= MOVE_TOP;
- }
- if (moving_edges == MOVE_TOP) {
- moving_edges |= MOVE_LEFT;
- }
- if (moving_edges == MOVE_RIGHT) {
- moving_edges |= MOVE_BOTTOM;
- }
- if (moving_edges == MOVE_BOTTOM) {
- moving_edges |= MOVE_RIGHT;
- }
- return moving_edges;
- }
-
- private RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy) {
- RectF newCrop = null;
- // Fix opposite corner in place and move sides
- if (moving_corner == BOTTOM_RIGHT) {
- newCrop = new RectF(r.left, r.top, r.left + r.width() + dx, r.top + r.height()
- + dy);
- } else if (moving_corner == BOTTOM_LEFT) {
- newCrop = new RectF(r.right - r.width() + dx, r.top, r.right, r.top + r.height()
- + dy);
- } else if (moving_corner == TOP_LEFT) {
- newCrop = new RectF(r.right - r.width() + dx, r.bottom - r.height() + dy,
- r.right, r.bottom);
- } else if (moving_corner == TOP_RIGHT) {
- newCrop = new RectF(r.left, r.bottom - r.height() + dy, r.left
- + r.width() + dx, r.bottom);
- }
- return newCrop;
+ /**
+ * Rotates first d bits in integer x to the left some number of times.
+ */
+ private int bitCycleLeft(int x, int times, int d) {
+ int mask = (1 << d) - 1;
+ int mout = x & mask;
+ times %= d;
+ int hi = mout >> (d - times);
+ int low = (mout << times) & mask;
+ int ret = x & ~mask;
+ ret |= low;
+ ret |= hi;
+ return ret;
}
- private void moveEdges(float dX, float dY) {
- RectF crop = mBounded.getInner();
-
- Matrix mc = getCropBoundDisplayedMatrix();
-
- RectF photo = getLocalPhotoBounds();
- Matrix mp = getPhotoBoundDisplayedMatrix();
- float[] photoCorners = CropMath.getCornersFromRect(photo);
- float[] photoCenter = {
- photo.centerX(), photo.centerY()
- };
- mp.mapPoints(photoCorners);
- mp.mapPoints(photoCenter);
-
- float minWidthHeight = mMinSideSize;
-
- if (movingEdges == MOVE_BLOCK) {
- mBounded.moveInner(-dX, -dY);
- RectF r = mBounded.getInner();
- setCropBounds(r);
- return;
- } else {
- float dx = 0;
- float dy = 0;
-
- if ((movingEdges & MOVE_LEFT) != 0) {
- dx = Math.min(crop.left + dX, crop.right - minWidthHeight) - crop.left;
- }
- if ((movingEdges & MOVE_TOP) != 0) {
- dy = Math.min(crop.top + dY, crop.bottom - minWidthHeight) - crop.top;
- }
- if ((movingEdges & MOVE_RIGHT) != 0) {
- dx = Math.max(crop.right + dX, crop.left + minWidthHeight)
- - crop.right;
- }
- if ((movingEdges & MOVE_BOTTOM) != 0) {
- dy = Math.max(crop.bottom + dY, crop.top + minWidthHeight)
- - crop.bottom;
- }
-
- if (mFixAspectRatio) {
- float[] l1 = {
- crop.left, crop.bottom
- };
- float[] l2 = {
- crop.right, crop.top
- };
- if (movingEdges == TOP_LEFT || movingEdges == BOTTOM_RIGHT) {
- l1[1] = crop.top;
- l2[1] = crop.bottom;
- }
- float[] b = {
- l1[0] - l2[0], l1[1] - l2[1]
- };
- float[] disp = {
- dx, dy
- };
- float[] bUnit = GeometryMath.normalize(b);
- float sp = GeometryMath.scalarProjection(disp, bUnit);
- dx = sp * bUnit[0];
- dy = sp * bUnit[1];
- RectF newCrop = fixedCornerResize(crop, movingEdges, dx, dy);
-
- mBounded.fixedAspectResizeInner(newCrop);
- newCrop = mBounded.getInner();
- setCropBounds(newCrop);
- return;
- } else {
- if ((movingEdges & MOVE_LEFT) != 0) {
- crop.left += dx;
- }
- if ((movingEdges & MOVE_TOP) != 0) {
- crop.top += dy;
- }
- if ((movingEdges & MOVE_RIGHT) != 0) {
- crop.right += dx;
- }
- if ((movingEdges & MOVE_BOTTOM) != 0) {
- crop.bottom += dy;
- }
- }
+ /**
+ * Find the selected edge or corner in screen coordinates.
+ */
+ private int decode(int movingEdges, float rotation) {
+ int rot = CropMath.constrainedRotation(rotation);
+ switch (rot) {
+ case 90:
+ return bitCycleLeft(movingEdges, 1, 4);
+ case 180:
+ return bitCycleLeft(movingEdges, 2, 4);
+ case 270:
+ return bitCycleLeft(movingEdges, 3, 4);
+ default:
+ return movingEdges;
}
- mBounded.resizeInner(crop);
- crop = mBounded.getInner();
- setCropBounds(crop);
- }
-
- private void drawIndicator(Canvas canvas, Drawable indicator, 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);
}
- @Override
- protected void setActionDown(float x, float y) {
- super.setActionDown(x, y);
- detectMovingEdges(x + mOffset[0], y + mOffset[1]);
-
- }
-
- @Override
- protected void setActionUp() {
- super.setActionUp();
- movingEdges = 0;
- }
-
- @Override
- protected void setActionMove(float x, float y) {
-
- if (movingEdges != 0) {
- moveEdges(x - mCurrentX, y - mCurrentY);
+ private void forceStateConsistency() {
+ MasterImage master = MasterImage.getImage();
+ Bitmap image = master.getFiltersOnlyImage();
+ int width = image.getWidth();
+ int height = image.getHeight();
+ if (mCropObj == null || !mUpdateHolder.equals(mGeometry)
+ || mImageBounds.width() != width || mImageBounds.height() != height
+ || !mLocalRep.getCrop().equals(mUpdateHolder.crop)) {
+ mImageBounds.set(0, 0, width, height);
+ mGeometry.set(mUpdateHolder);
+ mLocalRep.setCrop(mUpdateHolder.crop);
+ RectF scaledCrop = new RectF(mUpdateHolder.crop);
+ FilterCropRepresentation.findScaledCrop(scaledCrop, width, height);
+ mCropObj = new CropObject(mImageBounds, scaledCrop, (int) mUpdateHolder.straighten);
+ mState = Mode.NONE;
+ clearDisplay();
}
- super.setActionMove(x, y);
-
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- setActionUp();
- cropSetup();
- invalidate();
- }
-
- private void cropSetup() {
- RectF crop = getLocalCropBounds();
- Matrix m = getCropBoundDisplayedMatrix();
- m.mapRect(crop);
- if (mFixAspectRatio) {
- CropMath.fixAspectRatio(crop, mAspectWidth, mAspectHeight);
- }
- float dCentX = getWidth() / 2;
- float dCentY = getHeight() / 2;
-
- BoundedRect r = getBoundedCrop(crop);
- crop = r.getInner();
- if (!setCropBounds(crop)) {
- float h = mMinSideSize / 2;
- float wScale = 1;
- float hScale = mAspectHeight / mAspectWidth;
- if (hScale < 1) {
- wScale = mAspectWidth / mAspectHeight;
- hScale = 1;
- }
- crop.set(dCentX - h * wScale, dCentY - h * hScale, dCentX + h * wScale, dCentY + h
- * hScale);
- if (mFixAspectRatio) {
- CropMath.fixAspectRatio(crop, mAspectWidth, mAspectHeight);
- }
- r.setInner(crop);
- crop = r.getInner();
- if (!setCropBounds(crop)) {
- crop.set(dCentX - h, dCentY - h, dCentX + h, dCentY + h);
- r.setInner(crop);
- crop = r.getInner();
- setCropBounds(crop);
- }
- }
- }
-
- @Override
- public void imageLoaded() {
- super.imageLoaded();
- syncLocalToMasterGeometry();
- clear();
- invalidate();
+ super.onSizeChanged(w, h, oldw, oldh);
+ clearDisplay();
}
@Override
- protected void gainedVisibility() {
- float rot = getLocalRotation();
- // if has changed orientation via rotate
- if (((int) ((rot - mLastRot) / 90)) % 2 != 0) {
- swapAspect();
- }
- cropSetup();
- mFirstDraw = true;
- }
-
- @Override
- public void resetParameter() {
- super.resetParameter();
- }
-
- @Override
- protected void lostVisibility() {
- mLastRot = getLocalRotation();
- }
-
- private void drawRuleOfThird(Canvas canvas, RectF bounds, Paint p) {
- 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;
- }
- }
-
- @Override
- protected void drawShape(Canvas canvas, Bitmap image) {
- gPaint.setAntiAlias(true);
- gPaint.setARGB(255, 255, 255, 255);
-
- if (mFirstDraw) {
- cropSetup();
- mFirstDraw = false;
- }
-
- RectF crop = drawTransformed(canvas, image, gPaint, mOffset);
- gPaint.setColor(mBorderColor);
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
-
- boolean doThirds = true;
-
- if (mFixAspectRatio) {
- float spotlightX = 0;
- float spotlightY = 0;
- if (mCropExtras != null) {
- spotlightX = mCropExtras.getSpotlightX();
- spotlightY = mCropExtras.getSpotlightY();
- }
- if (mDoingCropIntentAction && spotlightX > 0 && spotlightY > 0) {
- float sx = crop.width() * spotlightX;
- float sy = crop.height() * spotlightY;
- float cx = crop.centerX();
- float cy = crop.centerY();
- RectF r1 = new RectF(cx - sx / 2, cy - sy / 2, cx + sx / 2, cy + sy / 2);
- float temp = sx;
- sx = sy;
- sy = temp;
- RectF r2 = new RectF(cx - sx / 2, cy - sy / 2, cx + sx / 2, cy + sy / 2);
- canvas.drawRect(r1, gPaint);
- canvas.drawRect(r2, gPaint);
- doThirds = false;
- } else {
- float w = crop.width();
- float h = crop.height();
- float diag = (float) Math.sqrt(w * w + h * h);
-
- float dash_len = 20;
- int num_intervals = (int) (diag / dash_len);
- float[] tl = {
- crop.left, crop.top
- };
- float centX = tl[0] + w / 2;
- float centY = tl[1] + h / 2 + 5;
- float[] br = {
- crop.right, crop.bottom
- };
- float[] vec = GeometryMath.getUnitVectorFromPoints(tl, br);
-
- float[] counter = tl;
- for (int x = 0; x < num_intervals; x++) {
- float tempX = counter[0] + vec[0] * dash_len;
- float tempY = counter[1] + vec[1] * dash_len;
- if ((x % 2) == 0 && Math.abs(x - num_intervals / 2) > 2) {
- canvas.drawLine(counter[0], counter[1], tempX, tempY, gPaint);
- }
- counter[0] = tempX;
- counter[1] = tempY;
- }
-
- gPaint.setTextAlign(Paint.Align.CENTER);
- gPaint.setTextSize(mAspectTextSize);
- canvas.drawText(mAspect, centX, centY, gPaint);
- }
- }
-
- if (doThirds) {
- drawRuleOfThird(canvas, crop, gPaint);
-
+ public void onDraw(Canvas canvas) {
+ Bitmap bitmap = MasterImage.getImage().getFiltersOnlyImage();
+ if (!mValidDraw || bitmap == null) {
+ return;
}
-
- RectF scaledCrop = crop;
- boolean notMoving = (movingEdges == 0);
- if (mFixAspectRatio) {
- if ((movingEdges == TOP_LEFT) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.top);
- }
- if ((movingEdges == TOP_RIGHT) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.top);
- }
- if ((movingEdges == BOTTOM_LEFT) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.bottom);
- }
- if ((movingEdges == BOTTOM_RIGHT) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.bottom);
- }
- } else {
- if (((movingEdges & MOVE_TOP) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top);
- }
- if (((movingEdges & MOVE_BOTTOM) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.bottom);
- }
- if (((movingEdges & MOVE_LEFT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.centerY());
- }
- if (((movingEdges & MOVE_RIGHT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.centerY());
+ forceStateConsistency();
+ mImageBounds.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ // If display matrix doesn't exist, create it and its dependencies
+ if (mDisplayCropMatrix == null || mDisplayMatrix == null || mDisplayMatrixInverse == null) {
+ mDisplayMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry,
+ bitmap.getWidth(), bitmap.getHeight(), canvas.getWidth(), canvas.getHeight());
+ float straighten = mGeometry.straighten;
+ mGeometry.straighten = 0;
+ mDisplayCropMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry,
+ bitmap.getWidth(), bitmap.getHeight(), canvas.getWidth(), canvas.getHeight());
+ mGeometry.straighten = straighten;
+ mDisplayMatrixInverse = new Matrix();
+ mDisplayMatrixInverse.reset();
+ if (!mDisplayCropMatrix.invert(mDisplayMatrixInverse)) {
+ Log.w(TAG, "could not invert display matrix");
+ mDisplayMatrixInverse = null;
+ return;
}
+ // Scale min side and tolerance by display matrix scale factor
+ mCropObj.setMinInnerSideSize(mDisplayMatrixInverse.mapRadius(mMinSideSize));
+ mCropObj.setTouchTolerance(mDisplayMatrixInverse.mapRadius(mTouchTolerance));
}
- }
-
- public void setAspectButton(int itemId) {
- switch (itemId) {
- case R.id.crop_menu_1to1: {
- String t = getActivity().getString(R.string.aspect1to1_effect);
- apply(1, 1);
- setAspectString(t);
- break;
- }
- case R.id.crop_menu_4to3: {
- String t = getActivity().getString(R.string.aspect4to3_effect);
- apply(4, 3);
- setAspectString(t);
- break;
- }
- case R.id.crop_menu_3to4: {
- String t = getActivity().getString(R.string.aspect3to4_effect);
- apply(3, 4);
- setAspectString(t);
- break;
- }
- case R.id.crop_menu_5to7: {
- String t = getActivity().getString(R.string.aspect5to7_effect);
- apply(5, 7);
- setAspectString(t);
- break;
- }
- case R.id.crop_menu_7to5: {
- String t = getActivity().getString(R.string.aspect7to5_effect);
- apply(7, 5);
- setAspectString(t);
- break;
- }
- case R.id.crop_menu_none: {
- String t = getActivity().getString(R.string.aspectNone_effect);
- applyClear();
- setAspectString(t);
- break;
- }
- case R.id.crop_menu_original: {
- String t = getActivity().getString(R.string.aspectOriginal_effect);
- applyOriginal();
- setAspectString(t);
- break;
- }
+ // Draw actual bitmap
+ mPaint.reset();
+ mPaint.setAntiAlias(true);
+ mPaint.setFilterBitmap(true);
+ canvas.drawBitmap(bitmap, mDisplayMatrix, mPaint);
+ mCropObj.getInnerBounds(mScreenCropBounds);
+ RectF outer = mCropObj.getOuterBounds();
+ FilterCropRepresentation.findNormalizedCrop(mScreenCropBounds, (int) outer.width(),
+ (int) outer.height());
+ FilterCropRepresentation.findScaledCrop(mScreenCropBounds, bitmap.getWidth(),
+ bitmap.getHeight());
+ if (mDisplayCropMatrix.mapRect(mScreenCropBounds)) {
+ // Draw crop rect and markers
+ CropDrawingUtils.drawCropRect(canvas, mScreenCropBounds);
+ CropDrawingUtils.drawRuleOfThird(canvas, mScreenCropBounds);
+ CropDrawingUtils.drawIndicators(canvas, mCropIndicator, mIndicatorSize,
+ mScreenCropBounds, mCropObj.isFixedAspect(),
+ decode(mCropObj.getSelectState(), mGeometry.rotation.value()));
}
- invalidate();
- }
-
- public void setFixedAspect(boolean fixedAspect) {
- mFixedAspect = fixedAspect;
- }
-
- @Override
- public boolean useUtilityPanel() {
- // Only shows the aspect ratio popup if we are not fixed
- return !mFixedAspect;
}
public void setEditor(EditorCrop editorCrop) {
mEditorCrop = editorCrop;
}
-
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java
index 67a093b..9722034 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java
@@ -72,12 +72,6 @@ public class ImageDraw extends ImageShow {
return (int) mCurrentSize;
}
- @Override
- public void updateImage() {
- super.updateImage();
- invalidate();
- }
-
float[] mTmpPoint = new float[2]; // so we do not malloc
@Override
public boolean onTouchEvent(MotionEvent event) {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java b/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
deleted file mode 100644
index fb39a9a..0000000
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
+++ /dev/null
@@ -1,160 +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.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.util.AttributeSet;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.editors.EditorFlip;
-import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation.Mirror;
-
-public class ImageFlip extends ImageGeometry {
-
- private static final Paint gPaint = new Paint();
- private static final float MIN_FLICK_DIST_FOR_FLIP= 0.1f;
- private static final String LOGTAG = "ImageFlip";
- private Mirror mNextFlip = Mirror.NONE;
- private EditorFlip mEditorFlip;
-
- public ImageFlip(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public ImageFlip(Context context) {
- super(context);
- }
-
- @Override
- protected void setActionDown(float x, float y) {
- super.setActionDown(x, y);
- }
-
- boolean hasRotated90(){
- int rot = constrainedRotation(getLocalRotation());
- return (rot / 90) % 2 != 0;
- }
-
- public void flip() {
- Mirror flip = getLocalMirror();
- boolean next = true;
- // Picks next flip in order from enum Mirror (wrapping)
- for (Mirror f : Mirror.values()) {
- if (next) {
- mNextFlip = f;
- next = false;
- }
- if (f.equals(flip)) {
- next = true;
- }
- }
- setLocalMirror(mNextFlip);
- }
-
- @Override
- protected void setActionMove(float x, float y) {
- super.setActionMove(x, y);
-
- float diffx = mTouchCenterX - x;
- float diffy = mTouchCenterY - y;
- float flick = getScaledMinFlick();
- if(hasRotated90()){
- float temp = diffx;
- diffx = diffy;
- diffy = temp;
- }
- if (Math.abs(diffx) >= flick) {
- // flick moving left/right
- Mirror flip = getLocalMirror();
- switch (flip) {
- case NONE:
- flip = Mirror.HORIZONTAL;
- break;
- case HORIZONTAL:
- flip = Mirror.NONE;
- break;
- case VERTICAL:
- flip = Mirror.BOTH;
- break;
- case BOTH:
- flip = Mirror.VERTICAL;
- break;
- default:
- flip = Mirror.NONE;
- break;
- }
- mNextFlip = flip;
- }
- if (Math.abs(diffy) >= flick) {
- // flick moving up/down
- Mirror flip = getLocalMirror();
- switch (flip) {
- case NONE:
- flip = Mirror.VERTICAL;
- break;
- case VERTICAL:
- flip = Mirror.NONE;
- break;
- case HORIZONTAL:
- flip = Mirror.BOTH;
- break;
- case BOTH:
- flip = Mirror.HORIZONTAL;
- break;
- default:
- flip = Mirror.NONE;
- break;
- }
- mNextFlip = flip;
- }
- }
-
- @Override
- protected void setActionUp() {
- super.setActionUp();
- setLocalMirror(mNextFlip);
- }
-
- @Override
- public void resetParameter() {
- super.resetParameter();
- mNextFlip = Mirror.NONE;
- }
-
- private float getScaledMinFlick() {
- RectF disp = getLocalDisplayBounds();
- float scaled = Math.min(disp.width(), disp.height()) * MIN_FLICK_DIST_FOR_FLIP
- / getLocalScale();
- return scaled;
- }
-
- @Override
- protected void drawShape(Canvas canvas, Bitmap image) {
- gPaint.setAntiAlias(true);
- gPaint.setARGB(255, 255, 255, 255);
- drawTransformedCropped(canvas, image, gPaint);
- }
-
- public void setEditor(EditorFlip editorFlip) {
- mEditorFlip = editorFlip;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java b/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
deleted file mode 100644
index 7d6c787..0000000
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
+++ /dev/null
@@ -1,527 +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.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation.Mirror;
-import com.android.gallery3d.filtershow.filters.FilterRepresentation;
-import com.android.gallery3d.filtershow.history.HistoryItem;
-import com.android.gallery3d.filtershow.pipeline.ImagePreset;
-
-public abstract class ImageGeometry extends ImageShow {
- protected boolean mVisibilityGained = false;
- private boolean mHasDrawn = false;
-
- protected static final float MAX_STRAIGHTEN_ANGLE = 45;
- protected static final float MIN_STRAIGHTEN_ANGLE = -45;
-
- protected float mCenterX;
- protected float mCenterY;
-
- protected float mCurrentX;
- protected float mCurrentY;
- protected float mTouchCenterX;
- protected float mTouchCenterY;
-
- // Local geometry data
- private GeometryMetadata mLocalGeometry = null;
- private RectF mLocalDisplayBounds = null;
- protected float mXOffset = 0;
- protected float mYOffset = 0;
-
- protected enum MODES {
- NONE, DOWN, UP, MOVE
- }
-
- protected MODES mMode = MODES.NONE;
-
- private static final String LOGTAG = "ImageGeometry";
-
- public ImageGeometry(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public ImageGeometry(Context context) {
- super(context);
- }
-
- private void setupLocalDisplayBounds(RectF b) {
- mLocalDisplayBounds = b;
- calculateLocalScalingFactorAndOffset();
- }
-
- protected static float angleFor(float dx, float dy) {
- return (float) (Math.atan2(dx, dy) * 180 / Math.PI);
- }
-
- protected static int snappedAngle(float angle) {
- float remainder = angle % 90;
- int current = (int) (angle / 90); // truncates
- if (remainder < -45) {
- --current;
- } else if (remainder > 45) {
- ++current;
- }
- return current * 90;
- }
-
- protected float getCurrentTouchAngle() {
- if (mCurrentX == mTouchCenterX && mCurrentY == mTouchCenterY) {
- return 0;
- }
- float dX1 = mTouchCenterX - mCenterX;
- float dY1 = mTouchCenterY - mCenterY;
- float dX2 = mCurrentX - mCenterX;
- float dY2 = mCurrentY - mCenterY;
-
- float angleA = angleFor(dX1, dY1);
- float angleB = angleFor(dX2, dY2);
- return (angleB - angleA) % 360;
- }
-
- protected float computeScale(float width, float height) {
- float imageWidth = mLocalGeometry.getPhotoBounds().width();
- float imageHeight = mLocalGeometry.getPhotoBounds().height();
- return GeometryMath.scale(imageWidth, imageHeight, width, height);
- }
-
- private void calculateLocalScalingFactorAndOffset() {
- if (mLocalGeometry == null || mLocalDisplayBounds == null)
- return;
- RectF imageBounds = mLocalGeometry.getPhotoBounds();
- float imageWidth = imageBounds.width();
- float imageHeight = imageBounds.height();
- float displayWidth = mLocalDisplayBounds.width();
- float displayHeight = mLocalDisplayBounds.height();
-
- mCenterX = displayWidth / 2;
- mCenterY = displayHeight / 2;
- mYOffset = (displayHeight - imageHeight) / 2.0f;
- mXOffset = (displayWidth - imageWidth) / 2.0f;
- updateScale();
- }
-
- @Override
- public void resetParameter() {
- super.resetParameter();
- setLocalRotation(0);
- setLocalStraighten(0);
- setLocalCropBounds(getLocalPhotoBounds());
- setLocalMirror(Mirror.NONE);
- saveAndSetPreset();
- invalidate();
- }
-
- // Overwrites local with master
- public void syncLocalToMasterGeometry() {
- mLocalGeometry = getGeometry();
- calculateLocalScalingFactorAndOffset();
- }
-
- protected RectF getLocalPhotoBounds() {
- return mLocalGeometry.getPhotoBounds();
- }
-
- protected RectF getLocalCropBounds() {
- return mLocalGeometry.getPreviewCropBounds();
- }
-
- protected RectF getLocalDisplayBounds() {
- return new RectF(mLocalDisplayBounds);
- }
-
- protected float getLocalScale() {
- return mLocalGeometry.getScaleFactor();
- }
-
- protected float getLocalRotation() {
- return mLocalGeometry.getRotation();
- }
-
- protected float getLocalStraighten() {
- return mLocalGeometry.getStraightenRotation();
- }
-
- protected void setLocalScale(float s) {
- mLocalGeometry.setScaleFactor(s);
- }
-
- protected void updateScale() {
- RectF bounds = getUntranslatedStraightenCropBounds(mLocalGeometry.getPhotoBounds(),
- getLocalStraighten());
- float zoom = computeScale(bounds.width(), bounds.height());
- setLocalScale(zoom);
- }
-
- protected void setLocalRotation(int r) {
- mLocalGeometry.setRotation(r);
- updateScale();
- }
-
- /**
- * Constrains rotation to be in [0, 90, 180, 270].
- */
- protected int constrainedRotation(float rotation) {
- int r = (int) ((rotation % 360) / 90);
- r = (r < 0) ? (r + 4) : r;
- return r * 90;
- }
-
- protected boolean isHeightWidthSwapped() {
- return ((int) (getLocalRotation() / 90)) % 2 != 0;
- }
-
- protected void setLocalStraighten(float r) {
- mLocalGeometry.setStraightenRotation(r);
- updateScale();
- }
-
- protected void setLocalCropBounds(RectF c) {
- mLocalGeometry.setCropBounds(c);
- updateScale();
- }
-
- protected Mirror getLocalMirror() {
- return mLocalGeometry.getMirrorType();
- }
-
- protected void setLocalMirror(Mirror flip) {
- mLocalGeometry.setMirrorType(flip);
- }
-
- protected float getTotalLocalRotation() {
- return getLocalRotation() + getLocalStraighten();
- }
-
- protected static Path drawClosedPath(Canvas canvas, Paint paint, float[] points) {
- Path crop = new Path();
- crop.moveTo(points[0], points[1]);
- crop.lineTo(points[2], points[3]);
- crop.lineTo(points[4], points[5]);
- crop.lineTo(points[6], points[7]);
- crop.close();
- canvas.drawPath(crop, paint);
- return crop;
- }
-
- protected static float getNewHeightForWidthAspect(float width, float w, float h) {
- return width * h / w;
- }
-
- protected static float getNewWidthForHeightAspect(float height, float w, float h) {
- return height * w / h;
- }
-
- @Override
- protected void onVisibilityChanged(View changedView, int visibility) {
- super.onVisibilityChanged(changedView, visibility);
- if (visibility == View.VISIBLE) {
- mVisibilityGained = true;
- MasterImage.getImage().invalidateFiltersOnly();
- syncLocalToMasterGeometry();
- updateScale();
- gainedVisibility();
- } else {
- if (mVisibilityGained == true && mHasDrawn == true) {
- lostVisibility();
- }
- mVisibilityGained = false;
- mHasDrawn = false;
- }
- }
-
- protected void gainedVisibility() {
- // Override this stub.
- }
-
- protected void lostVisibility() {
- // Override this stub.
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- setupLocalDisplayBounds(new RectF(0, 0, w, h));
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getActionMasked()) {
- case (MotionEvent.ACTION_DOWN):
- setActionDown(event.getX(), event.getY());
- break;
- case (MotionEvent.ACTION_UP):
- setActionUp();
- saveAndSetPreset();
- break;
- case (MotionEvent.ACTION_MOVE):
- setActionMove(event.getX(), event.getY());
- break;
- default:
- setNoAction();
- }
- invalidate();
- return true;
- }
-
- protected int getLocalValue() {
- return 0; // Override this
- }
-
- protected void setActionDown(float x, float y) {
- mTouchCenterX = x;
- mTouchCenterY = y;
- mCurrentX = x;
- mCurrentY = y;
- mMode = MODES.DOWN;
- }
-
- protected void setActionMove(float x, float y) {
- mCurrentX = x;
- mCurrentY = y;
- mMode = MODES.MOVE;
- }
-
- protected void setActionUp() {
- mMode = MODES.UP;
- }
-
- protected void setNoAction() {
- mMode = MODES.NONE;
- }
-
- public void saveAndSetPreset() {
- FilterRepresentation lastAction = null;
- HistoryItem historyItem = MasterImage.getImage().getHistory().getLast();
- if (historyItem != null) {
- lastAction = historyItem.getFilterRepresentation();
- }
-
- if (lastAction != null
- && lastAction.getSerializationName().equalsIgnoreCase(
- GeometryMetadata.SERIALIZATION_NAME)) {
- getImagePreset().setGeometry(mLocalGeometry);
- resetImageCaches(this);
- } else {
- if (mLocalGeometry.hasModifications()) {
- ImagePreset copy = new ImagePreset(getImagePreset());
- copy.setGeometry(mLocalGeometry);
- // TODO: we should have multiple filter representations for each
- // of the different geometry operations we have, otherwise we cannot
- // differentiate them in the history/state
- MasterImage.getImage().setPreset(copy, copy.getGeometry(), true);
- }
- }
- MasterImage.getImage().notifyGeometryChange();
- invalidate();
- }
-
- public static RectF getUntranslatedStraightenCropBounds(RectF imageRect, float straightenAngle) {
- float deg = straightenAngle;
- if (deg < 0) {
- deg = -deg;
- }
- double a = Math.toRadians(deg);
- double sina = Math.sin(a);
- double cosa = Math.cos(a);
-
- double rw = imageRect.width();
- double rh = imageRect.height();
- double h1 = rh * rh / (rw * sina + rh * cosa);
- double h2 = rh * rw / (rw * cosa + rh * sina);
- double hh = Math.min(h1, h2);
- double ww = hh * rw / rh;
-
- float left = (float) ((rw - ww) * 0.5f);
- float top = (float) ((rh - hh) * 0.5f);
- float right = (float) (left + ww);
- float bottom = (float) (top + hh);
-
- return new RectF(left, top, right, bottom);
- }
-
- protected RectF straightenBounds() {
- RectF bounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
- getLocalStraighten());
- float scale = computeScale(getWidth(), getHeight());
- bounds = GeometryMath.scaleRect(bounds, scale);
- float dx = (getWidth() / 2) - bounds.centerX();
- float dy = (getHeight() / 2) - bounds.centerY();
- bounds.offset(dx, dy);
- return bounds;
- }
-
- protected static void drawRotatedShadows(Canvas canvas, Paint p, RectF innerBounds,
- RectF outerBounds,
- float rotation, float centerX, float centerY) {
- canvas.save();
- canvas.rotate(rotation, centerX, centerY);
-
- float x = (outerBounds.left - outerBounds.right);
- float y = (outerBounds.top - outerBounds.bottom);
- float longest = (float) Math.sqrt(x * x + y * y) / 2;
- float minX = centerX - longest;
- float maxX = centerX + longest;
- float minY = centerY - longest;
- float maxY = centerY + longest;
- canvas.drawRect(minX, minY, innerBounds.right, innerBounds.top, p);
- canvas.drawRect(minX, innerBounds.top, innerBounds.left, maxY, p);
- canvas.drawRect(innerBounds.left, innerBounds.bottom, maxX, maxY,
- p);
- canvas.drawRect(innerBounds.right, minY, maxX,
- innerBounds.bottom, p);
- canvas.rotate(-rotation, centerX, centerY);
- canvas.restore();
- }
-
- protected void drawShadows(Canvas canvas, Paint p, RectF innerBounds) {
- float w = getWidth();
- float h = getHeight();
- canvas.drawRect(0f, 0f, w, innerBounds.top, p);
- canvas.drawRect(0f, innerBounds.top, innerBounds.left, innerBounds.bottom, p);
- canvas.drawRect(innerBounds.right, innerBounds.top, w, innerBounds.bottom, p);
- canvas.drawRect(0f, innerBounds.bottom, w, h, p);
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- Bitmap image = getFiltersOnlyImage();
- if (image == null) {
- invalidate();
- return;
- }
- mHasDrawn = true;
-
- drawShape(canvas, image);
- }
-
- protected void drawShape(Canvas canvas, Bitmap image) {
- // TODO: Override this stub.
- }
-
- /**
- * Sets up inputs for buildCenteredPhotoMatrix and buildWanderingCropMatrix
- * and returns the scale factor.
- */
- protected float getTransformState(RectF photo, RectF crop, float[] displayCenter) {
- RectF photoBounds = getLocalPhotoBounds();
- RectF cropBounds = getLocalCropBounds();
- float scale = computeScale(getWidth(), getHeight());
- // checks if local rotation is an odd multiple of 90.
- if (isHeightWidthSwapped()) {
- scale = computeScale(getHeight(), getWidth());
- }
- // put in screen coordinates
- if (crop != null) {
- crop.set(GeometryMath.scaleRect(cropBounds, scale));
- }
- if (photo != null) {
- photo.set(GeometryMath.scaleRect(photoBounds, scale));
- }
- if (displayCenter != null && displayCenter.length >= 2) {
- displayCenter[0] = getWidth() / 2f;
- displayCenter[1] = getHeight() / 2f;
- }
- return scale;
- }
-
- protected RectF drawTransformed(Canvas canvas, Bitmap photo, Paint p, float[] offset) {
- p.setARGB(255, 0, 0, 0);
- float[] displayCenter = new float[2];
- RectF scaledCrop = new RectF();
- RectF scaledPhoto = new RectF();
- float scale = getTransformState(scaledPhoto, scaledCrop, displayCenter);
- Matrix m = GeometryMetadata.buildCenteredPhotoMatrix(scaledPhoto, scaledCrop,
- getLocalRotation(), getLocalStraighten(), getLocalMirror(), displayCenter);
-
- Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop,
- getLocalRotation(), getLocalStraighten(), getLocalMirror(), displayCenter);
- m1.mapRect(scaledCrop);
- Path path = new Path();
- scaledCrop.offset(-offset[0], -offset[1]);
- path.addRect(scaledCrop, Path.Direction.CCW);
-
- m.preScale(scale, scale);
- m.postTranslate(-offset[0], -offset[1]);
- canvas.save();
- canvas.drawBitmap(photo, m, p);
- canvas.restore();
-
- p.setColor(Color.WHITE);
- p.setStyle(Style.STROKE);
- p.setStrokeWidth(2);
- canvas.drawPath(path, p);
-
- p.setColor(mBackgroundColor);
- p.setAlpha(128);
- p.setStyle(Paint.Style.FILL);
- drawShadows(canvas, p, scaledCrop);
- return scaledCrop;
- }
-
- protected void drawTransformedCropped(Canvas canvas, Bitmap photo, Paint p) {
- RectF photoBounds = getLocalPhotoBounds();
- RectF cropBounds = getLocalCropBounds();
- float imageWidth = cropBounds.width();
- float imageHeight = cropBounds.height();
- float scale = GeometryMath.scale(imageWidth, imageHeight, getWidth(), getHeight());
- // checks if local rotation is an odd multiple of 90.
- if (isHeightWidthSwapped()) {
- scale = GeometryMath.scale(imageWidth, imageHeight, getHeight(), getWidth());
- }
- // put in screen coordinates
- RectF scaledCrop = GeometryMath.scaleRect(cropBounds, scale);
- RectF scaledPhoto = GeometryMath.scaleRect(photoBounds, scale);
- float[] displayCenter = {
- getWidth() / 2f, getHeight() / 2f
- };
- Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop,
- getLocalRotation(), getLocalStraighten(), getLocalMirror(), displayCenter);
- float[] cropCenter = {
- scaledCrop.centerX(), scaledCrop.centerY()
- };
- m1.mapPoints(cropCenter);
- GeometryMetadata.concatRecenterMatrix(m1, cropCenter, displayCenter);
- m1.preRotate(getLocalStraighten(), scaledPhoto.centerX(), scaledPhoto.centerY());
- m1.preScale(scale, scale);
-
- p.setARGB(255, 0, 0, 0);
- canvas.save();
- canvas.drawBitmap(photo, m1, p);
- canvas.restore();
-
- p.setColor(mBackgroundColor);
- p.setStyle(Paint.Style.FILL);
- scaledCrop.offset(displayCenter[0] - scaledCrop.centerX(), displayCenter[1]
- - scaledCrop.centerY());
- RectF display = new RectF(0, 0, getWidth(), getHeight());
- drawRotatedShadows(canvas, p, scaledCrop, display, getLocalRotation(), getWidth() / 2,
- getHeight() / 2);
- }
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageMirror.java b/src/com/android/gallery3d/filtershow/imageshow/ImageMirror.java
new file mode 100644
index 0000000..26c49b1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageMirror.java
@@ -0,0 +1,78 @@
+/*
+ * 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.imageshow;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.gallery3d.filtershow.editors.EditorMirror;
+import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
+
+public class ImageMirror extends ImageShow {
+ private static final String TAG = ImageMirror.class.getSimpleName();
+ private EditorMirror mEditorMirror;
+ private FilterMirrorRepresentation mLocalRep = new FilterMirrorRepresentation();
+ private GeometryHolder mDrawHolder = new GeometryHolder();
+
+ public ImageMirror(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ImageMirror(Context context) {
+ super(context);
+ }
+
+ public void setFilterMirrorRepresentation(FilterMirrorRepresentation rep) {
+ mLocalRep = (rep == null) ? new FilterMirrorRepresentation() : rep;
+ }
+
+ public void flip() {
+ mLocalRep.cycle();
+ invalidate();
+ }
+
+ public FilterMirrorRepresentation getFinalRepresentation() {
+ return mLocalRep;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // Treat event as handled.
+ return true;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ MasterImage master = MasterImage.getImage();
+ Bitmap image = master.getFiltersOnlyImage();
+ if (image == null) {
+ return;
+ }
+ GeometryMathUtils.initializeHolder(mDrawHolder, mLocalRep);
+ GeometryMathUtils.drawTransformedCropped(mDrawHolder, canvas, image, getWidth(),
+ getHeight());
+ }
+
+ public void setEditor(EditorMirror editorFlip) {
+ mEditorMirror = editorFlip;
+ }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java b/src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java
index c58dd5f..fd57141 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java
@@ -58,12 +58,6 @@ public abstract class ImagePoint extends ImageShow {
}
@Override
- public void updateImage() {
- super.updateImage();
- invalidate();
- }
-
- @Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java b/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
index 87b5d33..5186c09 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
@@ -19,20 +19,18 @@ package com.android.gallery3d.filtershow.imageshow;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Paint;
import android.util.AttributeSet;
+import android.view.MotionEvent;
-import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.editors.EditorRotate;
+import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
-public class ImageRotate extends ImageGeometry {
-
- private float mBaseAngle = 0;
- private float mAngle = 0;
-
- private final boolean mSnapToNinety = true;
+public class ImageRotate extends ImageShow {
private EditorRotate mEditorRotate;
- private static final String LOGTAG = "ImageRotate";
+ private static final String TAG = ImageRotate.class.getSimpleName();
+ private FilterRotateRepresentation mLocalRep = new FilterRotateRepresentation();
+ private GeometryHolder mDrawHolder = new GeometryHolder();
public ImageRotate(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -42,51 +40,39 @@ public class ImageRotate extends ImageGeometry {
super(context);
}
- private static final Paint gPaint = new Paint();
-
- private void computeValue() {
- float angle = getCurrentTouchAngle();
- mAngle = (mBaseAngle - angle) % 360;
+ public void setFilterRotateRepresentation(FilterRotateRepresentation rep) {
+ mLocalRep = (rep == null) ? new FilterRotateRepresentation() : rep;
}
public void rotate() {
- mAngle += 90;
- mAngle = snappedAngle(mAngle);
- mAngle %= 360;
- setLocalRotation((int) mAngle);
- }
-
- @Override
- protected void setActionDown(float x, float y) {
- super.setActionDown(x, y);
- mBaseAngle = mAngle = getLocalRotation();
+ mLocalRep.rotateCW();
+ invalidate();
}
- @Override
- protected void setActionMove(float x, float y) {
- super.setActionMove(x, y);
- computeValue();
- setLocalRotation((int) mAngle % 360);
+ public FilterRotateRepresentation getFinalRepresentation() {
+ return mLocalRep;
}
@Override
- protected void setActionUp() {
- super.setActionUp();
- if (mSnapToNinety) {
- setLocalRotation(snappedAngle(mAngle % 360));
- }
+ public boolean onTouchEvent(MotionEvent event) {
+ // Treat event as handled.
+ return true;
}
- @Override
public int getLocalValue() {
- return constrainedRotation(snappedAngle(getLocalRotation()));
+ return mLocalRep.getRotation().value();
}
@Override
- protected void drawShape(Canvas canvas, Bitmap image) {
- gPaint.setAntiAlias(true);
- gPaint.setARGB(255, 255, 255, 255);
- drawTransformedCropped(canvas, image, gPaint);
+ public void onDraw(Canvas canvas) {
+ MasterImage master = MasterImage.getImage();
+ Bitmap image = master.getFiltersOnlyImage();
+ if (image == null) {
+ return;
+ }
+ GeometryMathUtils.initializeHolder(mDrawHolder, mLocalRep);
+ GeometryMathUtils.drawTransformedCropped(mDrawHolder, canvas, image, canvas.getWidth(),
+ canvas.getHeight());
}
public void setEditor(EditorRotate editorRotate) {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 1ff4227..6278b2a 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -37,7 +37,6 @@ import android.widget.LinearLayout;
import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.FilterShowActivity;
-import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
import com.android.gallery3d.filtershow.tools.SaveImage;
@@ -87,10 +86,6 @@ public class ImageShow extends View implements OnGestureListener,
}
InteractionMode mInteractionMode = InteractionMode.NONE;
- protected GeometryMetadata getGeometry() {
- return new GeometryMetadata(getImagePreset().getGeometry());
- }
-
private FilterShowActivity mActivity = null;
public FilterShowActivity getActivity() {
@@ -154,16 +149,6 @@ public class ImageShow extends View implements OnGestureListener,
return MasterImage.getImage().getCurrentFilter();
}
- public Rect getImageBounds() {
- Rect dst = new Rect();
- getImagePreset().getGeometry().getPhotoBounds().roundOut(dst);
- return dst;
- }
-
- public Rect getImageCropBounds() {
- return GeometryMath.roundNearest(getImagePreset().getGeometry().getPreviewCropBounds());
- }
-
/* consider moving the following 2 methods into a subclass */
/**
* This function calculates a Image to Screen Transformation matrix
@@ -172,16 +157,14 @@ public class ImageShow extends View implements OnGestureListener,
* @return Image to Screen transformation matrix
*/
protected Matrix getImageToScreenMatrix(boolean reflectRotation) {
- GeometryMetadata geo = getImagePreset().getGeometry();
- if (geo == null
- || MasterImage.getImage().getOriginalBounds() == null) {
+ MasterImage master = MasterImage.getImage();
+ if (master.getOriginalBounds() == null) {
return new Matrix();
}
- Matrix m = geo.getOriginalToScreen(reflectRotation,
- MasterImage.getImage().getOriginalBounds().width(),
- MasterImage.getImage().getOriginalBounds().height(), getWidth(), getHeight());
- Point translate = MasterImage.getImage().getTranslation();
- float scaleFactor = MasterImage.getImage().getScaleFactor();
+ Matrix m = GeometryMathUtils.getImageToScreenMatrix(master.getPreset().getGeometryFilters(),
+ reflectRotation, master.getOriginalBounds(), getWidth(), getHeight());
+ Point translate = master.getTranslation();
+ float scaleFactor = master.getScaleFactor();
m.postTranslate(translate.x, translate.y);
m.postScale(scaleFactor, scaleFactor, getWidth() / 2.0f, getHeight() / 2.0f);
return m;
@@ -237,7 +220,7 @@ public class ImageShow extends View implements OnGestureListener,
drawImage(canvas, getFilteredImage(), true);
Bitmap highresPreview = MasterImage.getImage().getHighresImage();
if (highresPreview != null) {
- drawImage(canvas, highresPreview, false);
+ drawImage(canvas, highresPreview, true);
}
canvas.restore();
@@ -278,7 +261,7 @@ public class ImageShow extends View implements OnGestureListener,
Rect s = new Rect(0, 0, image.getWidth(),
image.getHeight());
- float scale = GeometryMath.scale(image.getWidth(), image.getHeight(), getWidth(),
+ float scale = GeometryMathUtils.scale(image.getWidth(), image.getHeight(), getWidth(),
getHeight());
float w = image.getWidth() * scale;
@@ -360,33 +343,12 @@ public class ImageShow extends View implements OnGestureListener,
MasterImage.getImage().addListener(this);
}
- private void imageSizeChanged(Bitmap image) {
- if (image == null || getImagePreset() == null)
- return;
- float w = image.getWidth();
- float h = image.getHeight();
- GeometryMetadata geo = getImagePreset().getGeometry();
- RectF pb = geo.getPhotoBounds();
- if (w == pb.width() && h == pb.height()) {
- return;
- }
- RectF r = new RectF(0, 0, w, h);
- geo.setPhotoBounds(r);
- geo.setCropBounds(r);
- getImagePreset().setGeometry(geo);
- }
-
public void updateImage() {
invalidate();
- Bitmap bitmap = MasterImage.getImage().getOriginalBitmapLarge();
- if (bitmap != null) {
- imageSizeChanged(bitmap);
- }
}
public void imageLoaded() {
updateImage();
- invalidate();
}
public void saveImage(FilterShowActivity filterShowActivity, File file) {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
index 17df2b7..ff75dcc 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
@@ -19,21 +19,52 @@ package com.android.gallery3d.filtershow.imageshow;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
+import android.view.MotionEvent;
-import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.editors.EditorStraighten;
+import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
-public class ImageStraighten extends ImageGeometry {
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ImageStraighten extends ImageShow {
+ private static final String TAG = ImageStraighten.class.getSimpleName();
private float mBaseAngle = 0;
private float mAngle = 0;
+ private float mInitialAngle = 0;
+ private boolean mFirstDrawSinceUp = false;
private EditorStraighten mEditorStraighten;
+ private FilterStraightenRepresentation mLocalRep = new FilterStraightenRepresentation();
+ private RectF mPriorCropAtUp = new RectF();
+ private RectF mDrawRect = new RectF();
+ private Path mDrawPath = new Path();
+ private GeometryHolder mDrawHolder = new GeometryHolder();
+ private enum MODES {
+ NONE, MOVE
+ }
+ private MODES mState = MODES.NONE;
+ private static final float MAX_STRAIGHTEN_ANGLE
+ = FilterStraightenRepresentation.MAX_STRAIGHTEN_ANGLE;
+ private static final float MIN_STRAIGHTEN_ANGLE
+ = FilterStraightenRepresentation.MIN_STRAIGHTEN_ANGLE;
+ private float mCurrentX;
+ private float mCurrentY;
+ private float mTouchCenterX;
+ private float mTouchCenterY;
+ private RectF mCrop = new RectF();
+ private final Paint mPaint = new Paint();
- private static final String LOGTAG = "ImageStraighten";
- private static final Paint gPaint = new Paint();
public ImageStraighten(Context context) {
super(context);
}
@@ -42,23 +73,76 @@ public class ImageStraighten extends ImageGeometry {
super(context, attrs);
}
- @Override
- protected void setActionDown(float x, float y) {
- super.setActionDown(x, y);
- mBaseAngle = mAngle = getLocalStraighten();
+ public void setFilterStraightenRepresentation(FilterStraightenRepresentation rep) {
+ mLocalRep = (rep == null) ? new FilterStraightenRepresentation() : rep;
+ mInitialAngle = mBaseAngle = mAngle = mLocalRep.getStraighten();
}
- private void setCropToStraighten(){
- setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
- getLocalStraighten()));
+ public Collection<FilterRepresentation> getFinalRepresentation() {
+ ArrayList<FilterRepresentation> reps = new ArrayList<FilterRepresentation>(2);
+ reps.add(mLocalRep);
+ if (mInitialAngle != mLocalRep.getStraighten()) {
+ reps.add(new FilterCropRepresentation(mCrop));
+ }
+ return reps;
}
@Override
- protected void setActionMove(float x, float y) {
- super.setActionMove(x, y);
- computeValue();
- setLocalStraighten(mAngle);
- setCropToStraighten();
+ public boolean onTouchEvent(MotionEvent event) {
+ float x = event.getX();
+ float y = event.getY();
+
+ switch (event.getActionMasked()) {
+ case (MotionEvent.ACTION_DOWN):
+ if (mState == MODES.NONE) {
+ mTouchCenterX = x;
+ mTouchCenterY = y;
+ mCurrentX = x;
+ mCurrentY = y;
+ mState = MODES.MOVE;
+ mBaseAngle = mAngle;
+ }
+ break;
+ case (MotionEvent.ACTION_UP):
+ if (mState == MODES.MOVE) {
+ mState = MODES.NONE;
+ mCurrentX = x;
+ mCurrentY = y;
+ computeValue();
+ mFirstDrawSinceUp = true;
+ }
+ break;
+ case (MotionEvent.ACTION_MOVE):
+ if (mState == MODES.MOVE) {
+ mCurrentX = x;
+ mCurrentY = y;
+ computeValue();
+ }
+ break;
+ default:
+ break;
+ }
+ invalidate();
+ return true;
+ }
+
+ private static float angleFor(float dx, float dy) {
+ return (float) (Math.atan2(dx, dy) * 180 / Math.PI);
+ }
+
+ private float getCurrentTouchAngle() {
+ float centerX = getWidth() / 2f;
+ float centerY = getHeight() / 2f;
+ if (mCurrentX == mTouchCenterX && mCurrentY == mTouchCenterY) {
+ return 0;
+ }
+ float dX1 = mTouchCenterX - centerX;
+ float dY1 = mTouchCenterY - centerY;
+ float dX2 = mCurrentX - centerX;
+ float dY2 = mCurrentY - centerY;
+ float angleA = angleFor(dX1, dY1);
+ float angleB = angleFor(dX2, dY2);
+ return (angleB - angleA) % 360;
}
private void computeValue() {
@@ -68,62 +152,105 @@ public class ImageStraighten extends ImageGeometry {
mAngle = Math.min(MAX_STRAIGHTEN_ANGLE, mAngle);
}
- @Override
- protected void lostVisibility() {
- saveAndSetPreset();
+ private static void getUntranslatedStraightenCropBounds(RectF outRect, float straightenAngle) {
+ float deg = straightenAngle;
+ if (deg < 0) {
+ deg = -deg;
+ }
+ double a = Math.toRadians(deg);
+ double sina = Math.sin(a);
+ double cosa = Math.cos(a);
+ double rw = outRect.width();
+ double rh = outRect.height();
+ double h1 = rh * rh / (rw * sina + rh * cosa);
+ double h2 = rh * rw / (rw * cosa + rh * sina);
+ double hh = Math.min(h1, h2);
+ double ww = hh * rw / rh;
+ float left = (float) ((rw - ww) * 0.5f);
+ float top = (float) ((rh - hh) * 0.5f);
+ float right = (float) (left + ww);
+ float bottom = (float) (top + hh);
+ outRect.set(left, top, right, bottom);
}
- @Override
- protected void gainedVisibility(){
- setCropToStraighten();
+ private void updateCurrentCrop(Matrix m, GeometryHolder h, RectF tmp, int imageWidth,
+ int imageHeight, int viewWidth, int viewHeight) {
+ if (GeometryMathUtils.needsDimensionSwap(h.rotation)) {
+ tmp.set(0, 0, imageHeight, imageWidth);
+ } else {
+ tmp.set(0, 0, imageWidth, imageHeight);
+ }
+ float scale = GeometryMathUtils.scale(imageWidth, imageHeight, viewWidth, viewHeight);
+ GeometryMathUtils.scaleRect(tmp, scale);
+ getUntranslatedStraightenCropBounds(tmp, mAngle);
+ tmp.offset(viewWidth / 2f - tmp.centerX(), viewHeight / 2f - tmp.centerY());
+ h.straighten = 0;
+ Matrix m1 = GeometryMathUtils.getFullGeometryToScreenMatrix(h, imageWidth,
+ imageHeight, viewWidth, viewHeight);
+ m.reset();
+ m1.invert(m);
+ mCrop.set(tmp);
+ m.mapRect(mCrop);
+ FilterCropRepresentation.findNormalizedCrop(mCrop, imageWidth, imageHeight);
}
- @Override
- protected void setActionUp() {
- super.setActionUp();
- setCropToStraighten();
- }
@Override
- public void onNewValue(int value) {
- setLocalStraighten(GeometryMath.clamp(value, MIN_STRAIGHTEN_ANGLE, MAX_STRAIGHTEN_ANGLE));
- invalidate();
- }
+ public void onDraw(Canvas canvas) {
+ MasterImage master = MasterImage.getImage();
+ Bitmap image = master.getFiltersOnlyImage();
+ if (image == null) {
+ return;
+ }
+ GeometryMathUtils.initializeHolder(mDrawHolder, mLocalRep);
+ mDrawHolder.straighten = mAngle;
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+ int viewWidth = canvas.getWidth();
+ int viewHeight = canvas.getHeight();
- @Override
- protected int getLocalValue() {
- return (int) getLocalStraighten();
- }
+ // Get matrix for drawing bitmap
+ Matrix m = GeometryMathUtils.getFullGeometryToScreenMatrix(mDrawHolder, imageWidth,
+ imageHeight, viewWidth, viewHeight);
+ mPaint.reset();
+ mPaint.setAntiAlias(true);
+ mPaint.setFilterBitmap(true);
+ canvas.drawBitmap(image, m, mPaint);
- @Override
- protected void drawShape(Canvas canvas, Bitmap image) {
- float [] o = {0, 0};
- RectF bounds = drawTransformed(canvas, image, gPaint, o);
+ mPaint.setFilterBitmap(false);
+ mPaint.setColor(Color.WHITE);
+ mPaint.setStrokeWidth(2);
+ mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ updateCurrentCrop(m, mDrawHolder, mDrawRect, imageWidth,
+ imageHeight, viewWidth, viewHeight);
+ if (mFirstDrawSinceUp) {
+ mPriorCropAtUp.set(mCrop);
+ mLocalRep.setStraighten(mAngle);
+ mFirstDrawSinceUp = false;
+ }
// Draw the grid
- gPaint.setARGB(255, 255, 255, 255);
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- RectF display = getLocalDisplayBounds();
- float dWidth = display.width();
- float dHeight = display.height();
-
- if (mMode == MODES.MOVE) {
+ if (mState == MODES.MOVE) {
canvas.save();
- canvas.clipRect(bounds);
-
+ canvas.clipRect(mDrawRect);
int n = 16;
- float step = dWidth / n;
+ float step = viewWidth / n;
float p = 0;
for (int i = 1; i < n; i++) {
p = i * step;
- gPaint.setARGB(60, 255, 255, 255);
- canvas.drawLine(p, 0, p, dHeight, gPaint);
- canvas.drawLine(0, p, dWidth, p, gPaint);
+ mPaint.setAlpha(60);
+ canvas.drawLine(p, 0, p, viewHeight, mPaint);
+ canvas.drawLine(0, p, viewHeight, p, mPaint);
}
canvas.restore();
}
+ mPaint.reset();
+ mPaint.setColor(Color.WHITE);
+ mPaint.setStyle(Style.STROKE);
+ mPaint.setStrokeWidth(3);
+ mDrawPath.reset();
+ mDrawPath.addRect(mDrawRect, Path.Direction.CW);
+ canvas.drawPath(mDrawPath, mPaint);
}
public void setEditor(EditorStraighten editorStraighten) {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index 45ee5d7..92e57bf 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -82,9 +82,6 @@ public class MasterImage implements RenderingRequestCaller {
private Vector<ImageShow> mObservers = new Vector<ImageShow>();
private FilterRepresentation mCurrentFilterRepresentation;
- private Vector<GeometryListener> mGeometryListeners = new Vector<GeometryListener>();
-
- private GeometryMetadata mPreviousGeometry = null;
private float mScaleFactor = 1.0f;
private float mMaxScaleFactor = 3.0f; // TODO: base this on the current view / image
@@ -95,20 +92,6 @@ public class MasterImage implements RenderingRequestCaller {
private boolean mShowsOriginal;
- final private static int NEW_GEOMETRY = 1;
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case NEW_GEOMETRY: {
- hasNewGeometry();
- break;
- }
- }
- }
- };
-
private MasterImage() {
}
@@ -243,39 +226,15 @@ public class MasterImage implements RenderingRequestCaller {
preset.showFilters();
}
mPreset = preset;
- setGeometry();
mPreset.fillImageStateAdapter(mState);
if (addToHistory) {
HistoryItem historyItem = new HistoryItem(mPreset, change);
mHistory.addHistoryItem(historyItem);
}
updatePresets(true);
- GeometryMetadata geo = mPreset.getGeometry();
- if (!geo.equals(mPreviousGeometry)) {
- notifyGeometryChange();
- }
- mPreviousGeometry = new GeometryMetadata(geo);
mActivity.updateCategories();
}
- private void setGeometry() {
- Bitmap image = getOriginalBitmapLarge();
- if (image == null) {
- return;
- }
- float w = image.getWidth();
- float h = image.getHeight();
- GeometryMetadata geo = mPreset.getGeometry();
- RectF pb = geo.getPhotoBounds();
- if (w == pb.width() && h == pb.height()) {
- return;
- }
- RectF r = new RectF(0, 0, w, h);
- geo.setPhotoBounds(r);
- geo.setCropBounds(r);
- mPreset.setGeometry(geo);
- }
-
public void onHistoryItemClick(int position) {
HistoryItem historyItem = mHistory.getItem(position);
// We need a copy from the history
@@ -337,16 +296,6 @@ public class MasterImage implements RenderingRequestCaller {
return mPreviewPreset;
}
- public void setOriginalGeometry(Bitmap originalBitmapLarge) {
- GeometryMetadata geo = getPreset().getGeometry();
- float w = originalBitmapLarge.getWidth();
- float h = originalBitmapLarge.getHeight();
- RectF r = new RectF(0, 0, w, h);
- geo.setPhotoBounds(r);
- geo.setCropBounds(r);
- getPreset().setGeometry(geo);
- }
-
public Bitmap getFilteredImage() {
mPreviewBuffer.swapConsumerIfNeeded(); // get latest bitmap
Buffer consumer = mPreviewBuffer.getConsumer();
@@ -450,14 +399,16 @@ public class MasterImage implements RenderingRequestCaller {
}
private Matrix getImageToScreenMatrix(boolean reflectRotation) {
- GeometryMetadata geo = mPreset.getGeometry();
- if (geo == null || getOriginalBounds() == null
- || mImageShowSize.x == 0) {
+ if (getOriginalBounds() == null || mImageShowSize.x == 0 || mImageShowSize.y == 0) {
return new Matrix();
}
- Matrix m = geo.getOriginalToScreen(reflectRotation,
- getOriginalBounds().width(),
- getOriginalBounds().height(), mImageShowSize.x, mImageShowSize.y);
+ Matrix m = GeometryMathUtils.getImageToScreenMatrix(mPreset.getGeometryFilters(),
+ reflectRotation, getOriginalBounds(), mImageShowSize.x, mImageShowSize.y);
+ if (m == null) {
+ m = new Matrix();
+ m.reset();
+ return m;
+ }
Point translate = getTranslation();
float scaleFactor = getScaleFactor();
m.postTranslate(translate.x, translate.y);
@@ -516,6 +467,7 @@ public class MasterImage implements RenderingRequestCaller {
}
if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
mFiltersOnlyBitmap = request.getBitmap();
+ notifyObservers();
needsCheckModification = true;
}
if (request.getType() == RenderingRequest.PARTIAL_RENDERING
@@ -538,24 +490,6 @@ public class MasterImage implements RenderingRequestCaller {
sMasterImage = null;
}
- public void addGeometryListener(GeometryListener listener) {
- mGeometryListeners.add(listener);
- }
-
- public void notifyGeometryChange() {
- if (mHandler.hasMessages(NEW_GEOMETRY)) {
- return;
- }
- mHandler.sendEmptyMessage(NEW_GEOMETRY);
- }
-
- public void hasNewGeometry() {
- updatePresets(true);
- for (GeometryListener listener : mGeometryListeners) {
- listener.geometryChanged();
- }
- }
-
public float getScaleFactor() {
return mScaleFactor;
}
diff --git a/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java
index 10b6c49..e0269e9 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java
@@ -90,7 +90,9 @@ public class CacheProcessing {
cacheBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);
if (findBaseImageIndex > -1) {
FilterRepresentation representation = filters.elementAt(findBaseImageIndex);
- cacheBitmap = environment.applyRepresentation(representation, cacheBitmap);
+ if (representation.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) {
+ cacheBitmap = environment.applyRepresentation(representation, cacheBitmap);
+ }
mSteps.elementAt(findBaseImageIndex).representation = representation.copy();
mSteps.elementAt(findBaseImageIndex).cache = cacheBitmap;
}
@@ -115,7 +117,9 @@ public class CacheProcessing {
}
for (int i = findBaseImageIndex; i <= similarUpToIndex; i++) {
FilterRepresentation representation = filters.elementAt(i);
- cacheBitmap = environment.applyRepresentation(representation, cacheBitmap);
+ if (representation.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) {
+ cacheBitmap = environment.applyRepresentation(representation, cacheBitmap);
+ }
if (DEBUG) {
Log.v(LOGTAG, " - " + i + " => apply " + representation.getName());
}
@@ -134,7 +138,9 @@ public class CacheProcessing {
FilterRepresentation representation = filters.elementAt(i);
CacheStep currentStep = mSteps.elementAt(i);
cacheBitmap = cacheBitmap.copy(Bitmap.Config.ARGB_8888, true);
- cacheBitmap = environment.applyRepresentation(representation, cacheBitmap);
+ if (representation.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) {
+ cacheBitmap = environment.applyRepresentation(representation, cacheBitmap);
+ }
currentStep.representation = representation.copy();
currentStep.cache = cacheBitmap;
if (DEBUG) {
diff --git a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java
index beba993..155ddaa 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java
@@ -26,8 +26,7 @@ import android.util.Log;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.FiltersManager;
-import com.android.gallery3d.filtershow.filters.ImageFilterGeometry;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import java.util.Vector;
@@ -39,7 +38,6 @@ public class CachingPipeline implements PipelineInterface {
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static volatile RenderScript sRS = null;
- private static volatile Resources sResources = null;
private FiltersManager mFiltersManager = null;
private volatile Bitmap mOriginalBitmap = null;
@@ -57,13 +55,10 @@ public class CachingPipeline implements PipelineInterface {
private volatile int mWidth = 0;
private volatile int mHeight = 0;
- private volatile GeometryMetadata mPreviousGeometry = null;
private volatile float mPreviewScaleFactor = 1.0f;
private volatile float mHighResPreviewScaleFactor = 1.0f;
private volatile String mName = "";
- private ImageFilterGeometry mGeometry = null;
-
public CachingPipeline(FiltersManager filtersManager, String name) {
mFiltersManager = filtersManager;
mName = name;
@@ -79,7 +74,6 @@ public class CachingPipeline implements PipelineInterface {
destroyRenderScriptContext();
}
sRS = RenderScript.create(context);
- sResources = context.getResources();
}
public static synchronized void destroyRenderScriptContext() {
@@ -87,7 +81,6 @@ public class CachingPipeline implements PipelineInterface {
sRS.destroy();
}
sRS = null;
- sResources = null;
}
public void stop() {
@@ -112,7 +105,6 @@ public class CachingPipeline implements PipelineInterface {
mFiltersOnlyOriginalAllocation.destroy();
mFiltersOnlyOriginalAllocation = null;
}
- mPreviousGeometry = null;
mPreviewScaleFactor = 1.0f;
mHighResPreviewScaleFactor = 1.0f;
@@ -190,15 +182,6 @@ public class CachingPipeline implements PipelineInterface {
return false;
}
- GeometryMetadata geometry = preset.getGeometry();
- if (mPreviousGeometry != null && geometry.equals(mPreviousGeometry)) {
- return false;
- }
-
- if (DEBUG) {
- Log.v(LOGTAG, "geometry has changed");
- }
-
RenderScript RS = getRenderScriptContext();
Allocation filtersOnlyOriginalAllocation = mFiltersOnlyOriginalAllocation;
@@ -216,7 +199,6 @@ public class CachingPipeline implements PipelineInterface {
originalAllocation.destroy();
}
- mPreviousGeometry = new GeometryMetadata(geometry);
return true;
}
@@ -333,14 +315,7 @@ public class CachingPipeline implements PipelineInterface {
}
public Bitmap renderGeometryIcon(Bitmap bitmap, ImagePreset preset) {
- // Called by RenderRequest on the main thread
- // TODO: change this -- we should reuse a pool of bitmaps instead...
- if (mGeometry == null) {
- mGeometry = new ImageFilterGeometry();
- }
- mGeometry.useRepresentation(preset.getGeometry());
- return mGeometry.apply(bitmap, mPreviewScaleFactor,
- FilterEnvironment.QUALITY_PREVIEW);
+ return GeometryMathUtils.applyGeometryRepresentations(preset.getGeometryFilters(), bitmap);
}
public void compute(SharedBuffer buffer, ImagePreset preset, int type) {
diff --git a/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java b/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java
index 29608bf..4fac956 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java
@@ -17,10 +17,14 @@
package com.android.gallery3d.filtershow.pipeline;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
import android.support.v8.renderscript.Allocation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation.Rotation;
import com.android.gallery3d.filtershow.filters.FiltersManagerInterface;
import com.android.gallery3d.filtershow.filters.ImageFilter;
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
index 9bb3e00..64643e4 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
@@ -36,7 +36,7 @@ import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
import com.android.gallery3d.filtershow.filters.FiltersManager;
import com.android.gallery3d.filtershow.filters.ImageFilter;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.state.State;
import com.android.gallery3d.filtershow.state.StateAdapter;
@@ -45,6 +45,8 @@ import com.android.gallery3d.util.UsageStatistics;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Vector;
public class ImagePreset {
@@ -65,17 +67,8 @@ public class ImagePreset {
public ImagePreset(ImagePreset source) {
for (int i = 0; i < source.mFilters.size(); i++) {
- FilterRepresentation representation = null;
FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i);
- if (sourceRepresentation instanceof GeometryMetadata) {
- GeometryMetadata geoData = new GeometryMetadata();
- GeometryMetadata srcGeo = (GeometryMetadata) sourceRepresentation;
- geoData.set(srcGeo);
- representation = geoData;
- } else {
- representation = sourceRepresentation.copy();
- }
- mFilters.add(representation);
+ mFilters.add(sourceRepresentation.copy());
}
}
@@ -91,9 +84,24 @@ public class ImagePreset {
return representation;
}
+ private static boolean sameSerializationName(String a, String b) {
+ if (a != null && b != null) {
+ return a.equals(b);
+ } else {
+ return a == null && b == null;
+ }
+ }
+
+ public static boolean sameSerializationName(FilterRepresentation a, FilterRepresentation b) {
+ if (a == null || b == null) {
+ return false;
+ }
+ return sameSerializationName(a.getSerializationName(), b.getSerializationName());
+ }
+
public int getPositionForRepresentation(FilterRepresentation representation) {
for (int i = 0; i < mFilters.size(); i++) {
- if (mFilters.elementAt(i).getFilterClass() == representation.getFilterClass()) {
+ if (sameSerializationName(mFilters.elementAt(i), representation)) {
return i;
}
}
@@ -118,7 +126,8 @@ public class ImagePreset {
return -1;
}
- public FilterRepresentation getFilterRepresentationCopyFrom(FilterRepresentation filterRepresentation) {
+ public FilterRepresentation getFilterRepresentationCopyFrom(
+ FilterRepresentation filterRepresentation) {
// TODO: add concept of position in the filters (to allow multiple instances)
if (filterRepresentation == null) {
return null;
@@ -134,22 +143,19 @@ public class ImagePreset {
return representation;
}
- public void updateFilterRepresentation(FilterRepresentation representation) {
- if (representation == null) {
- return;
+ public void updateFilterRepresentations(Collection<FilterRepresentation> reps) {
+ for (FilterRepresentation r : reps) {
+ updateOrAddFilterRepresentation(r);
}
- if (representation instanceof GeometryMetadata) {
- setGeometry((GeometryMetadata) representation);
+ }
+
+ public void updateOrAddFilterRepresentation(FilterRepresentation rep) {
+ int pos = getPositionForRepresentation(rep);
+ if (pos != -1) {
+ mFilters.elementAt(pos).useParametersFrom(rep);
} else {
- int position = getPositionForRepresentation(representation);
- if (position == -1) {
- return;
- }
- FilterRepresentation old = mFilters.elementAt(position);
- old.useParametersFrom(representation);
+ addFilter(rep.copy());
}
- MasterImage.getImage().invalidatePreview();
- fillImageStateAdapter(MasterImage.getImage().getState());
}
public void setDoApplyGeometry(boolean value) {
@@ -164,25 +170,10 @@ public class ImagePreset {
return mDoApplyFilters;
}
- public GeometryMetadata getGeometry() {
- for (FilterRepresentation representation : mFilters) {
- if (representation instanceof GeometryMetadata) {
- return (GeometryMetadata) representation;
- }
- }
- GeometryMetadata geo = new GeometryMetadata();
- mFilters.add(0, geo); // Hard Requirement for now -- Geometry ought to be first.
- return geo;
- }
-
public boolean hasModifications() {
for (int i = 0; i < mFilters.size(); i++) {
FilterRepresentation filter = mFilters.elementAt(i);
- if (filter instanceof GeometryMetadata) {
- if (((GeometryMetadata) filter).hasModifications()) {
- return true;
- }
- } else if (!filter.isNil()) {
+ if (!filter.isNil()) {
return true;
}
}
@@ -191,10 +182,9 @@ public class ImagePreset {
public boolean isPanoramaSafe() {
for (FilterRepresentation representation : mFilters) {
- if (representation instanceof GeometryMetadata) {
- if (((GeometryMetadata) representation).hasModifications()) {
- return false;
- }
+ if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
+ && !representation.isNil()) {
+ return false;
}
if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER
&& !representation.isNil()) {
@@ -212,29 +202,6 @@ public class ImagePreset {
return true;
}
- public void setGeometry(GeometryMetadata representation) {
- GeometryMetadata geoData = getGeometry();
- if (geoData != representation) {
- geoData.set(representation);
- }
- }
-
- public boolean equals(ImagePreset preset) {
- if (!same(preset)) {
- return false;
- }
- if (mDoApplyFilters && preset.mDoApplyFilters) {
- for (int i = 0; i < preset.mFilters.size(); i++) {
- FilterRepresentation a = preset.mFilters.elementAt(i);
- FilterRepresentation b = mFilters.elementAt(i);
- if (!a.equals(b)) {
- return false;
- }
- }
- }
- return true;
- }
-
public boolean same(ImagePreset preset) {
if (preset == null) {
return false;
@@ -248,10 +215,6 @@ public class ImagePreset {
return false;
}
- if (mDoApplyGeometry && !getGeometry().equals(preset.getGeometry())) {
- return false;
- }
-
if (mDoApplyFilters != preset.mDoApplyFilters) {
if (mFilters.size() > 0 || preset.mFilters.size() > 0) {
return false;
@@ -262,10 +225,7 @@ public class ImagePreset {
for (int i = 0; i < preset.mFilters.size(); i++) {
FilterRepresentation a = preset.mFilters.elementAt(i);
FilterRepresentation b = mFilters.elementAt(i);
- if (a instanceof GeometryMetadata) {
- // Note: Geometry will always be at the same place
- continue;
- }
+
if (!a.same(b)) {
return false;
}
@@ -276,10 +236,6 @@ public class ImagePreset {
}
public int similarUpTo(ImagePreset preset) {
- if (!getGeometry().equals(preset.getGeometry())) {
- return -1;
- }
-
for (int i = 0; i < preset.mFilters.size(); i++) {
FilterRepresentation a = preset.mFilters.elementAt(i);
if (i < mFilters.size()) {
@@ -316,17 +272,16 @@ public class ImagePreset {
public void removeFilter(FilterRepresentation filterRepresentation) {
if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
- for (int i = 0; i < mFilters.size();i++) {
+ for (int i = 0; i < mFilters.size(); i++) {
if (mFilters.elementAt(i).getFilterType()
- == filterRepresentation.getFilterType()) {
+ == filterRepresentation.getFilterType()) {
mFilters.remove(i);
break;
}
}
} else {
for (int i = 0; i < mFilters.size(); i++) {
- if (mFilters.elementAt(i).getFilterClass()
- == filterRepresentation.getFilterClass()) {
+ if (sameSerializationName(mFilters.elementAt(i), filterRepresentation)) {
mFilters.remove(i);
break;
}
@@ -334,29 +289,27 @@ public class ImagePreset {
}
}
- // If the filter is an "None" effect or border, then just don't add this
- // filter.
+ // If the filter is an "None" effect or border, then just don't add this filter.
public void addFilter(FilterRepresentation representation) {
- if (representation instanceof GeometryMetadata) {
- setGeometry((GeometryMetadata) representation);
- return;
- }
if (representation instanceof FilterUserPresetRepresentation) {
ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset();
// user preset replace everything but geometry
- GeometryMetadata geometry = getGeometry();
mFilters.clear();
- mFilters.add(geometry);
for (int i = 0; i < preset.nbFilters(); i++) {
- FilterRepresentation rep = preset.getFilterRepresentation(i);
- if (!(representation instanceof GeometryMetadata)) {
- addFilter(rep);
- }
+ addFilter(preset.getFilterRepresentation(i));
}
mFilters.add(representation);
- return;
- }
- if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
+ } else if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
+ // Add geometry filter, removing duplicates and do-nothing operations.
+ for (int i = 0; i < mFilters.size(); i++) {
+ if (sameSerializationName(representation, mFilters.elementAt(i))) {
+ mFilters.remove(i);
+ }
+ }
+ if (!representation.isNil()) {
+ mFilters.add(representation);
+ }
+ } else if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
removeFilter(representation);
if (!isNoneBorderFilter(representation)) {
mFilters.add(representation);
@@ -421,13 +374,13 @@ public class ImagePreset {
private boolean isNoneFxFilter(FilterRepresentation representation) {
return representation instanceof FilterFxRepresentation &&
- ((FilterFxRepresentation)representation).getNameResource() == R.string.none;
+ ((FilterFxRepresentation) representation).getNameResource() == R.string.none;
}
public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) {
for (int i = 0; i < mFilters.size(); i++) {
FilterRepresentation representation = mFilters.elementAt(i);
- if (representation.getFilterClass() == filterRepresentation.getFilterClass()) {
+ if (sameSerializationName(representation, filterRepresentation)) {
return representation;
}
}
@@ -440,12 +393,32 @@ public class ImagePreset {
return applyBorder(bitmap, environment);
}
+ public Collection<FilterRepresentation> getGeometryFilters() {
+ ArrayList<FilterRepresentation> geometry = new ArrayList<FilterRepresentation>();
+ for (FilterRepresentation r : mFilters) {
+ if (r.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
+ geometry.add(r);
+ }
+ }
+ return geometry;
+ }
+
+ public FilterRepresentation getFilterWithSerializationName(String serializationName) {
+ for (FilterRepresentation r : mFilters) {
+ if (r != null) {
+ if (sameSerializationName(r.getSerializationName(), serializationName)) {
+ return r.copy();
+ }
+ }
+ }
+ return null;
+ }
+
public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) {
// Apply any transform -- 90 rotate, flip, straighten, crop
// Returns a new bitmap.
if (mDoApplyGeometry) {
- GeometryMetadata geoData = getGeometry();
- bitmap = environment.applyRepresentation(geoData, bitmap);
+ bitmap = GeometryMathUtils.applyGeometryRepresentations(getGeometryFilters(), bitmap);
}
return bitmap;
}
@@ -482,12 +455,13 @@ public class ImagePreset {
}
for (int i = from; i < to; i++) {
FilterRepresentation representation = mFilters.elementAt(i);
- if (representation instanceof GeometryMetadata) {
+ if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
// skip the geometry as it's already applied.
continue;
}
if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
- // for now, let's skip the border as it will be applied in applyBorder()
+ // for now, let's skip the border as it will be applied in
+ // applyBorder()
// TODO: might be worth getting rid of applyBorder.
continue;
}
@@ -506,7 +480,7 @@ public class ImagePreset {
}
public void applyBorder(Allocation in, Allocation out,
- boolean copyOut, FilterEnvironment environment) {
+ boolean copyOut, FilterEnvironment environment) {
FilterRepresentation border = getFilterRepresentationForType(
FilterRepresentation.TYPE_BORDER);
if (border != null && mDoApplyGeometry) {
@@ -522,7 +496,7 @@ public class ImagePreset {
}
public void applyFilters(int from, int to, Allocation in, Allocation out,
- FilterEnvironment environment) {
+ FilterEnvironment environment) {
if (mDoApplyFilters) {
if (from < 0) {
from = 0;
@@ -532,12 +506,8 @@ public class ImagePreset {
}
for (int i = from; i < to; i++) {
FilterRepresentation representation = mFilters.elementAt(i);
- if (representation instanceof GeometryMetadata) {
- // skip the geometry as it's already applied.
- continue;
- }
- if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
- // for now, let's skip the border as it will be applied in applyBorder()
+ if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
+ || representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
continue;
}
if (i > from) {
@@ -554,8 +524,8 @@ public class ImagePreset {
}
for (int i = 0; i < mFilters.size(); i++) {
FilterRepresentation representation = mFilters.elementAt(i);
- if (representation instanceof GeometryMetadata
- && ((GeometryMetadata) representation).hasModifications()) {
+ if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
+ && !representation.isNil()) {
return false;
}
if (!representation.supportsPartialRendering()) {
@@ -571,7 +541,7 @@ public class ImagePreset {
}
Vector<State> states = new Vector<State>();
for (FilterRepresentation filter : mFilters) {
- if (filter instanceof GeometryMetadata) {
+ if (filter.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
// TODO: supports Geometry representations in the state panel.
continue;
}
@@ -622,7 +592,7 @@ public class ImagePreset {
}
public void writeJson(JsonWriter writer, String name) {
- int numFilters = mFilters.size();
+ int numFilters = mFilters.size();
try {
writer.beginObject();
for (int i = 0; i < numFilters; i++) {
@@ -649,12 +619,13 @@ public class ImagePreset {
/**
* populates preset from JSON string
+ *
* @param filterString a JSON string
* @return true on success if false ImagePreset is undefined
*/
public boolean readJsonFromString(String filterString) {
if (DEBUG) {
- Log.v(LOGTAG,"reading preset: \""+filterString+"\"");
+ Log.v(LOGTAG, "reading preset: \"" + filterString + "\"");
}
StringReader sreader = new StringReader(filterString);
try {
@@ -666,7 +637,7 @@ public class ImagePreset {
}
reader.close();
} catch (Exception e) {
- Log.e(LOGTAG,"parsing the filter parameters:",e);
+ Log.e(LOGTAG, "parsing the filter parameters:", e);
return false;
}
return true;
@@ -674,6 +645,7 @@ public class ImagePreset {
/**
* populates preset from JSON stream
+ *
* @param sreader a JSON string
* @return true on success if false ImagePreset is undefined
*/
@@ -684,7 +656,7 @@ public class ImagePreset {
String name = sreader.nextName();
FilterRepresentation filter = creatFilterFromName(name);
if (filter == null) {
- Log.w(LOGTAG,"UNKNOWN FILTER! "+name);
+ Log.w(LOGTAG, "UNKNOWN FILTER! " + name);
return false;
}
filter.deSerializeRepresentation(sreader);
@@ -695,10 +667,7 @@ public class ImagePreset {
}
FilterRepresentation creatFilterFromName(String name) {
- // TODO: move these to FiltersManager pattern.
- if (GeometryMetadata.SERIALIZATION_NAME.equalsIgnoreCase(name)) {
- return new GeometryMetadata();
- } else if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) {
+ if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) {
return new FilterRotateRepresentation();
} else if (FilterMirrorRepresentation.SERIALIZATION_NAME.equals(name)) {
return new FilterMirrorRepresentation();
diff --git a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
index ab85110..8ea21ad 100644
--- a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
+++ b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
@@ -30,7 +30,7 @@ public class EditorManager {
editorPlaceHolder.addEditor(new EditorTinyPlanet());
editorPlaceHolder.addEditor(new EditorDraw());
editorPlaceHolder.addEditor(new EditorVignette());
- editorPlaceHolder.addEditor(new EditorFlip());
+ editorPlaceHolder.addEditor(new EditorMirror());
editorPlaceHolder.addEditor(new EditorRotate());
editorPlaceHolder.addEditor(new EditorStraighten());
editorPlaceHolder.addEditor(new EditorCrop());