summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/filtershow
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/filtershow')
-rw-r--r--src/com/android/gallery3d/filtershow/CropExtras.java121
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java297
-rw-r--r--src/com/android/gallery3d/filtershow/PanelController.java232
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java269
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilter.java60
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterBWBlue.java37
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterBWGreen.java37
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterBWRed.java37
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java3
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java26
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java68
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java (renamed from src/com/android/gallery3d/filtershow/filters/ImageFilterBW.java)31
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java47
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java94
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java47
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java3
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java157
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java20
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java36
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java12
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java23
-rw-r--r--src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java50
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java340
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/CropMath.java191
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java81
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java104
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java715
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java2
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java206
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageRedEyes.java148
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java2
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java60
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java18
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java5
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java50
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java4
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePreset.java4
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetBW.java33
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetBWBlue.java33
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetBWGreen.java33
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetBWRed.java33
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java45
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetOld.java38
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetSaturated.java35
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetXProcessing.java39
-rw-r--r--src/com/android/gallery3d/filtershow/tools/BitmapTask.java68
-rw-r--r--src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java22
-rw-r--r--src/com/android/gallery3d/filtershow/ui/FramedTextButton.java37
-rw-r--r--src/com/android/gallery3d/filtershow/ui/ImageCurves.java16
-rw-r--r--src/com/android/gallery3d/filtershow/ui/Spline.java18
57 files changed, 2688 insertions, 1483 deletions
diff --git a/src/com/android/gallery3d/filtershow/CropExtras.java b/src/com/android/gallery3d/filtershow/CropExtras.java
new file mode 100644
index 000000000..7ed8f1eb5
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/CropExtras.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import android.net.Uri;
+
+public class CropExtras {
+
+ public static final String KEY_CROPPED_RECT = "cropped-rect";
+ public static final String KEY_OUTPUT_X = "outputX";
+ public static final String KEY_OUTPUT_Y = "outputY";
+ public static final String KEY_SCALE = "scale";
+ public static final String KEY_SCALE_UP_IF_NEEDED = "scaleUpIfNeeded";
+ public static final String KEY_ASPECT_X = "aspectX";
+ public static final String KEY_ASPECT_Y = "aspectY";
+ public static final String KEY_SET_AS_WALLPAPER = "set-as-wallpaper";
+ public static final String KEY_RETURN_DATA = "return-data";
+ public static final String KEY_DATA = "data";
+ public static final String KEY_SPOTLIGHT_X = "spotlightX";
+ public static final String KEY_SPOTLIGHT_Y = "spotlightY";
+ public static final String KEY_SHOW_WHEN_LOCKED = "showWhenLocked";
+ public static final String KEY_OUTPUT_FORMAT = "outputFormat";
+
+ private int mOutputX = 0;
+ private int mOutputY = 0;
+ private boolean mScaleUp = true;
+ private int mAspectX = 0;
+ private int mAspectY = 0;
+ private boolean mSetAsWallpaper = false;
+ private boolean mReturnData = false;
+ private Uri mExtraOutput = null;
+ private String mOutputFormat = null;
+ private boolean mShowWhenLocked = false;
+ private float mSpotlightX = 0;
+ private float mSpotlightY = 0;
+
+ public CropExtras(int outputX, int outputY, boolean scaleUp, int aspectX, int aspectY,
+ boolean setAsWallpaper, boolean returnData, Uri extraOutput, String outputFormat,
+ boolean showWhenLocked, float spotlightX, float spotlightY) {
+ mOutputX = outputX;
+ mOutputY = outputY;
+ mScaleUp = scaleUp;
+ mAspectX = aspectX;
+ mAspectY = aspectY;
+ mSetAsWallpaper = setAsWallpaper;
+ mReturnData = returnData;
+ mExtraOutput = extraOutput;
+ mOutputFormat = outputFormat;
+ mShowWhenLocked = showWhenLocked;
+ mSpotlightX = spotlightX;
+ mSpotlightY = spotlightY;
+ }
+
+ public CropExtras(CropExtras c) {
+ this(c.mOutputX, c.mOutputY, c.mScaleUp, c.mAspectX, c.mAspectY, c.mSetAsWallpaper,
+ c.mReturnData, c.mExtraOutput, c.mOutputFormat, c.mShowWhenLocked,
+ c.mSpotlightX, c.mSpotlightY);
+ }
+
+ public int getOutputX() {
+ return mOutputX;
+ }
+
+ public int getOutputY() {
+ return mOutputY;
+ }
+
+ public boolean getScaleUp() {
+ return mScaleUp;
+ }
+
+ public int getAspectX() {
+ return mAspectX;
+ }
+
+ public int getAspectY() {
+ return mAspectY;
+ }
+
+ public boolean getSetAsWallpaper() {
+ return mSetAsWallpaper;
+ }
+
+ public boolean getReturnData() {
+ return mReturnData;
+ }
+
+ public Uri getExtraOutput() {
+ return mExtraOutput;
+ }
+
+ public String getOutputFormat() {
+ return mOutputFormat;
+ }
+
+ public boolean getShowWhenLocked() {
+ return mShowWhenLocked;
+ }
+
+ public float getSpotlightX() {
+ return mSpotlightX;
+ }
+
+ public float getSpotlightY() {
+ return mSpotlightY;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 94d318558..4198da020 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -20,6 +20,7 @@ import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.Activity;
import android.app.ProgressDialog;
+import android.app.WallpaperManager;
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Configuration;
@@ -32,6 +33,7 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
@@ -58,13 +60,19 @@ import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
import com.android.gallery3d.filtershow.filters.ImageFilterBwFilter;
import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
+import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
+import com.android.gallery3d.filtershow.filters.ImageFilterDownsample;
+import com.android.gallery3d.filtershow.filters.ImageFilterEdge;
import com.android.gallery3d.filtershow.filters.ImageFilterExposure;
import com.android.gallery3d.filtershow.filters.ImageFilterFx;
import com.android.gallery3d.filtershow.filters.ImageFilterHue;
+import com.android.gallery3d.filtershow.filters.ImageFilterKMeans;
+import com.android.gallery3d.filtershow.filters.ImageFilterNegative;
import com.android.gallery3d.filtershow.filters.ImageFilterParametricBorder;
import com.android.gallery3d.filtershow.filters.ImageFilterRS;
import com.android.gallery3d.filtershow.filters.ImageFilterSaturated;
import com.android.gallery3d.filtershow.filters.ImageFilterShadows;
+import com.android.gallery3d.filtershow.filters.ImageFilterSharpen;
import com.android.gallery3d.filtershow.filters.ImageFilterTinyPlanet;
import com.android.gallery3d.filtershow.filters.ImageFilterVibrance;
import com.android.gallery3d.filtershow.filters.ImageFilterVignette;
@@ -72,13 +80,13 @@ import com.android.gallery3d.filtershow.filters.ImageFilterWBalance;
import com.android.gallery3d.filtershow.imageshow.ImageBorder;
import com.android.gallery3d.filtershow.imageshow.ImageCrop;
import com.android.gallery3d.filtershow.imageshow.ImageFlip;
+import com.android.gallery3d.filtershow.imageshow.ImageRedEyes;
import com.android.gallery3d.filtershow.imageshow.ImageRotate;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.imageshow.ImageSmallBorder;
import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter;
import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
import com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet;
-import com.android.gallery3d.filtershow.imageshow.ImageWithIcon;
import com.android.gallery3d.filtershow.imageshow.ImageZoom;
import com.android.gallery3d.filtershow.presets.ImagePreset;
import com.android.gallery3d.filtershow.provider.SharedImageProvider;
@@ -90,6 +98,7 @@ import com.android.gallery3d.filtershow.ui.Spline;
import com.android.gallery3d.util.GalleryUtils;
import java.io.File;
+import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Vector;
@@ -97,14 +106,19 @@ import java.util.Vector;
public class FilterShowActivity extends Activity implements OnItemClickListener,
OnShareTargetSelectedListener {
- public static final String CROP_ACTION = "com.android.camera.action.EDITOR_CROP";
+ // fields for supporting crop action
+ public static final String CROP_ACTION = "com.android.camera.action.CROP";
+ private CropExtras mCropExtras = null;
+
public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
public static final String LAUNCH_FULLSCREEN = "launch-fullscreen";
+ public static final int MAX_BMAP_IN_INTENT = 990000;
private final PanelController mPanelController = new PanelController();
private ImageLoader mImageLoader = null;
private ImageShow mImageShow = null;
private ImageCurves mImageCurves = null;
private ImageBorder mImageBorders = null;
+ private ImageRedEyes mImageRedEyes = null;
private ImageStraighten mImageStraighten = null;
private ImageZoom mImageZoom = null;
private ImageCrop mImageCrop = null;
@@ -156,10 +170,13 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
ImageFilterRS.setRenderScriptContext(this);
ImageShow.setDefaultBackgroundColor(getResources().getColor(R.color.background_screen));
- ImageSmallFilter.setDefaultBackgroundColor(getResources().getColor(R.color.background_main_toolbar));
+ ImageSmallFilter.setDefaultBackgroundColor(getResources().getColor(
+ R.color.background_main_toolbar));
// TODO: get those values from XML.
ImageZoom.setZoomedSize(getPixelsFromDip(256));
FramedTextButton.setTextSize((int) getPixelsFromDip(14));
+ FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4));
+ FramedTextButton.setTriangleSize((int) getPixelsFromDip(10));
ImageShow.setTextSize((int) getPixelsFromDip(12));
ImageShow.setTextPadding((int) getPixelsFromDip(10));
ImageShow.setOriginalTextMargin((int) getPixelsFromDip(4));
@@ -202,8 +219,11 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mImageRotate = (ImageRotate) findViewById(R.id.imageRotate);
mImageFlip = (ImageFlip) findViewById(R.id.imageFlip);
mImageTinyPlanet = (ImageTinyPlanet) findViewById(R.id.imageTinyPlanet);
+ mImageRedEyes = (ImageRedEyes) findViewById(R.id.imageRedEyes);
+ mImageCrop.setAspectTextSize((int) getPixelsFromDip(18));
ImageCrop.setTouchTolerance((int) getPixelsFromDip(25));
+ ImageCrop.setMinCropSize((int) getPixelsFromDip(55));
mImageViews.add(mImageShow);
mImageViews.add(mImageCurves);
mImageViews.add(mImageBorders);
@@ -213,6 +233,10 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mImageViews.add(mImageRotate);
mImageViews.add(mImageFlip);
mImageViews.add(mImageTinyPlanet);
+ mImageViews.add(mImageRedEyes);
+ for (ImageShow imageShow : mImageViews) {
+ mImageLoader.addCacheListener(imageShow);
+ }
mListFx = findViewById(R.id.fxList);
mListBorders = findViewById(R.id.bordersList);
@@ -230,6 +254,11 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mGeometryButton = (ImageButton) findViewById(R.id.geometryButton);
mColorsButton = (ImageButton) findViewById(R.id.colorsButton);
+ mBottomPanelButtons.add(mFxButton);
+ mBottomPanelButtons.add(mBorderButton);
+ mBottomPanelButtons.add(mGeometryButton);
+ mBottomPanelButtons.add(mColorsButton);
+
mImageShow.setImageLoader(mImageLoader);
mImageCurves.setImageLoader(mImageLoader);
mImageCurves.setMaster(mImageShow);
@@ -247,6 +276,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mImageFlip.setMaster(mImageShow);
mImageTinyPlanet.setImageLoader(mImageLoader);
mImageTinyPlanet.setMaster(mImageShow);
+ mImageRedEyes.setImageLoader(mImageLoader);
+ mImageRedEyes.setMaster(mImageShow);
mPanelController.setActivity(this);
@@ -259,6 +290,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mPanelController.addImageView(findViewById(R.id.imageFlip));
mPanelController.addImageView(findViewById(R.id.imageZoom));
mPanelController.addImageView(findViewById(R.id.imageTinyPlanet));
+ mPanelController.addImageView(findViewById(R.id.imageRedEyes));
mPanelController.addPanel(mFxButton, mListFx, 0);
mPanelController.addPanel(mBorderButton, mListBorders, 1);
@@ -268,86 +300,45 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton));
mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton));
mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton));
+ mPanelController.addComponent(mGeometryButton, findViewById(R.id.redEyeButton));
mPanelController.addPanel(mColorsButton, mListColors, 3);
- int[] recastIDs = {
- R.id.tinyplanetButton,
- R.id.vignetteButton,
- R.id.vibranceButton,
- R.id.contrastButton,
- R.id.saturationButton,
- R.id.bwfilterButton,
- R.id.wbalanceButton,
- R.id.hueButton,
- R.id.exposureButton,
- R.id.shadowRecoveryButton
- };
ImageFilter[] filters = {
new ImageFilterTinyPlanet(),
+ new ImageFilterWBalance(),
+ new ImageFilterExposure(),
new ImageFilterVignette(),
- new ImageFilterVibrance(),
new ImageFilterContrast(),
+ new ImageFilterShadows(),
+ new ImageFilterVibrance(),
+ new ImageFilterSharpen(),
+ new ImageFilterCurves(),
+ new ImageFilterHue(),
new ImageFilterSaturated(),
new ImageFilterBwFilter(),
- new ImageFilterWBalance(),
- new ImageFilterHue(),
- new ImageFilterExposure(),
- new ImageFilterShadows()
+ new ImageFilterNegative(),
+ new ImageFilterEdge(),
+ new ImageFilterKMeans(),
+ new ImageFilterDownsample()
};
for (int i = 0; i < filters.length; i++) {
ImageSmallFilter fView = new ImageSmallFilter(this);
- View v = listColors.findViewById(recastIDs[i]);
- int pos = listColors.indexOfChild(v);
- listColors.removeView(v);
-
filters[i].setParameter(filters[i].getPreviewParameter());
- if (v instanceof ImageButtonTitle)
- filters[i].setName(((ImageButtonTitle) v).getText());
+ filters[i].setName(getString(filters[i].getTextId()));
fView.setImageFilter(filters[i]);
fView.setController(this);
fView.setImageLoader(mImageLoader);
- fView.setId(recastIDs[i]);
- mPanelController.addComponent(mColorsButton, fView);
- listColors.addView(fView, pos);
- }
-
- int[] overlayIDs = {
- R.id.sharpenButton,
- R.id.curvesButtonRGB
- };
- int[] overlayBitmaps = {
- R.drawable.filtershow_button_colors_sharpen,
- R.drawable.filtershow_button_colors_curve
- };
- int[] overlayNames = {
- R.string.sharpness,
- R.string.curvesRGB
- };
-
- for (int i = 0; i < overlayIDs.length; i++) {
- ImageWithIcon fView = new ImageWithIcon(this);
- View v = listColors.findViewById(overlayIDs[i]);
- int pos = listColors.indexOfChild(v);
- listColors.removeView(v);
- final int sid = overlayNames[i];
- ImageFilterExposure efilter = new ImageFilterExposure() {
- {
- mName = getString(sid);
- }
- };
- efilter.setParameter(-300);
- Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
- overlayBitmaps[i]);
-
- fView.setIcon(bitmap);
- fView.setImageFilter(efilter);
- fView.setController(this);
- fView.setImageLoader(mImageLoader);
- fView.setId(overlayIDs[i]);
+ fView.setId(filters[i].getButtonId());
+ if (filters[i].getOverlayBitmaps() != 0) {
+ Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
+ filters[i].getOverlayBitmaps());
+ fView.setOverlayBitmap(bitmap);
+ }
mPanelController.addComponent(mColorsButton, fView);
- listColors.addView(fView, pos);
+ mPanelController.addFilter(filters[i]);
+ listColors.addView(fView);
}
mPanelController.addView(findViewById(R.id.applyEffect));
@@ -389,8 +380,37 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
pickImage();
}
+ // Handle behavior for various actions
String action = intent.getAction();
if (action.equalsIgnoreCase(CROP_ACTION)) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ mCropExtras = new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0),
+ extras.getInt(CropExtras.KEY_OUTPUT_Y, 0),
+ extras.getBoolean(CropExtras.KEY_SCALE, true) &&
+ extras.getBoolean(CropExtras.KEY_SCALE_UP_IF_NEEDED, false),
+ extras.getInt(CropExtras.KEY_ASPECT_X, 0),
+ extras.getInt(CropExtras.KEY_ASPECT_Y, 0),
+ extras.getBoolean(CropExtras.KEY_SET_AS_WALLPAPER, false),
+ extras.getBoolean(CropExtras.KEY_RETURN_DATA, false),
+ (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT),
+ extras.getString(CropExtras.KEY_OUTPUT_FORMAT),
+ extras.getBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, false),
+ extras.getFloat(CropExtras.KEY_SPOTLIGHT_X),
+ extras.getFloat(CropExtras.KEY_SPOTLIGHT_Y));
+
+ if (mCropExtras.getShowWhenLocked()) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ }
+ mImageShow.getImagePreset().mGeoData.setCropExtras(mCropExtras);
+
+ mImageCrop.setExtras(mCropExtras);
+ String s = getString(R.string.Fixed);
+ mImageCrop.setAspectString(s);
+ mImageCrop.setCropActionFlag(true);
+ mPanelController.setFixedAspect(mCropExtras.getAspectX() > 0
+ && mCropExtras.getAspectY() > 0);
+ }
mPanelController.showComponent(findViewById(R.id.cropButton));
} else if (action.equalsIgnoreCase(TINY_PLANET_ACTION)) {
mPanelController.showComponent(findViewById(R.id.tinyplanetButton));
@@ -410,7 +430,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mLoadBitmapTask.execute(uri);
}
- private class LoadBitmapTask extends AsyncTask<Uri, Void, Boolean> {
+ private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
View mTinyPlanetButton;
int mBitmapSize;
@@ -421,19 +441,26 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
@Override
protected Boolean doInBackground(Uri... params) {
- mImageLoader.loadBitmap(params[0], mBitmapSize);
- publishProgress();
- return mImageLoader.queryLightCycle360();
+ if (!mImageLoader.loadBitmap(params[0], mBitmapSize)) {
+ return false;
+ }
+ publishProgress(mImageLoader.queryLightCycle360());
+ return true;
}
@Override
- protected void onProgressUpdate(Void... values) {
+ protected void onProgressUpdate(Boolean... values) {
super.onProgressUpdate(values);
- if (isCancelled()) return;
+ if (isCancelled()) {
+ return;
+ }
final View filters = findViewById(R.id.filtersPanel);
final View loading = findViewById(R.id.loading);
loading.setVisibility(View.GONE);
filters.setVisibility(View.VISIBLE);
+ if (values[0]) {
+ mTinyPlanetButton.setVisibility(View.VISIBLE);
+ }
}
@Override
@@ -441,9 +468,10 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
if (isCancelled()) {
return;
}
- if (result) {
- mTinyPlanetButton.setVisibility(View.VISIBLE);
+ if (!result) {
+ cannotLoadImage();
}
+
mLoadBitmapTask = null;
super.onPostExecute(result);
}
@@ -465,6 +493,10 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
if (mainPanelWidth == 0) {
mainPanelWidth = mainViewWidth;
}
+ int filtersPanelWidth = findViewById(R.id.filtersPanel).getWidth();
+ if (mainPanelWidth < filtersPanelWidth) {
+ mainPanelWidth = filtersPanelWidth;
+ }
int leftOver = mainViewWidth - mainPanelWidth - accessoryPanelWidth;
if (leftOver < 0) {
return -accessoryPanelWidth;
@@ -711,19 +743,29 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
// TODO: use listview
// TODO: load the borders straight from the filesystem
int p = 0;
- ImageFilter[] borders = new ImageFilter[7];
+ ImageFilter[] borders = new ImageFilter[12];
borders[p++] = new ImageFilterBorder(null);
Drawable npd1 = getResources().getDrawable(R.drawable.filtershow_border_4x5);
borders[p++] = new ImageFilterBorder(npd1);
Drawable npd2 = getResources().getDrawable(R.drawable.filtershow_border_brush);
borders[p++] = new ImageFilterBorder(npd2);
+ Drawable npd3 = getResources().getDrawable(R.drawable.filtershow_border_grunge);
+ borders[p++] = new ImageFilterBorder(npd3);
+ Drawable npd4 = getResources().getDrawable(R.drawable.filtershow_border_sumi_e);
+ borders[p++] = new ImageFilterBorder(npd4);
+ Drawable npd5 = getResources().getDrawable(R.drawable.filtershow_border_tape);
+ borders[p++] = new ImageFilterBorder(npd5);
borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize, 0);
borders[p++] = new ImageFilterParametricBorder(Color.BLACK, mImageBorderSize,
mImageBorderSize);
borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize, 0);
borders[p++] = new ImageFilterParametricBorder(Color.WHITE, mImageBorderSize,
mImageBorderSize);
+ int creamColor = Color.argb(255, 237, 237, 227);
+ borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize, 0);
+ borders[p++] = new ImageFilterParametricBorder(creamColor, mImageBorderSize,
+ mImageBorderSize);
ImageSmallFilter previousFilter = null;
for (int i = 0; i < p; i++) {
@@ -786,6 +828,22 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
}
}
+ public void disableFilterButtons() {
+ for (ImageButton b : mBottomPanelButtons) {
+ b.setEnabled(false);
+ b.setClickable(false);
+ b.setAlpha(0.4f);
+ }
+ }
+
+ public void enableFilterButtons() {
+ for (ImageButton b : mBottomPanelButtons) {
+ b.setEnabled(true);
+ b.setClickable(true);
+ b.setAlpha(1.0f);
+ }
+ }
+
// //////////////////////////////////////////////////////////////////////////////
// imageState panel...
@@ -867,7 +925,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
invalidateOptionsMenu();
}
- private void resetHistory() {
+ void resetHistory() {
mNullFxFilter.onClick(mNullFxFilter);
mNullBorderFilter.onClick(mNullBorderFilter);
@@ -980,17 +1038,88 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
}
}
+ private boolean mSaveToExtraUri = false;
+ private boolean mSaveAsWallpaper = false;
+ private boolean mReturnAsExtra = false;
+ private boolean outputted = false;
+
public void saveImage() {
- if (mImageShow.hasModifications()) {
- // Get the name of the album, to which the image will be saved
- File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri());
- int bucketId = GalleryUtils.getBucketId(saveDir.getPath());
- String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null);
- showSavingProgress(albumName);
- mImageShow.saveImage(this, null);
- } else {
- finish();
+ // boolean outputted = false;
+ if (mCropExtras != null) {
+ if (mCropExtras.getExtraOutput() != null) {
+ mSaveToExtraUri = true;
+ outputted = true;
+ }
+ if (mCropExtras.getSetAsWallpaper()) {
+ mSaveAsWallpaper = true;
+ outputted = true;
+ }
+ if (mCropExtras.getReturnData()) {
+
+ mReturnAsExtra = true;
+ outputted = true;
+ }
+
+ if (outputted) {
+ mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true);
+ showSavingProgress(null);
+ mImageShow.returnFilteredResult(this);
+ }
}
+ if (!outputted) {
+ if (mImageShow.hasModifications()) {
+ // Get the name of the album, to which the image will be saved
+ File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri());
+ int bucketId = GalleryUtils.getBucketId(saveDir.getPath());
+ String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null);
+ showSavingProgress(albumName);
+ mImageShow.saveImage(this, null);
+ } else {
+ done();
+ }
+ }
+ }
+
+ public void onFilteredResult(Bitmap filtered) {
+ Intent intent = new Intent();
+ intent.putExtra(CropExtras.KEY_CROPPED_RECT, mImageShow.getImageCropBounds());
+ if (mSaveToExtraUri) {
+ mImageShow.saveToUri(filtered, mCropExtras.getExtraOutput(),
+ mCropExtras.getOutputFormat(), this);
+ }
+ if (mSaveAsWallpaper) {
+ try {
+ WallpaperManager.getInstance(this).setBitmap(filtered);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "fail to set wall paper", e);
+ }
+ }
+ if (mReturnAsExtra) {
+ if (filtered != null) {
+ int bmapSize = filtered.getRowBytes() * filtered.getHeight();
+ /*
+ * Max size of Binder transaction buffer is 1Mb, so constrain
+ * Bitmap to be somewhat less than this, otherwise we get
+ * TransactionTooLargeExceptions.
+ */
+ if (bmapSize > MAX_BMAP_IN_INTENT) {
+ Log.w(LOGTAG, "Bitmap too large to be returned via intent");
+ } else {
+ intent.putExtra(CropExtras.KEY_DATA, filtered);
+ }
+ }
+ }
+ setResult(RESULT_OK, intent);
+ if (!mSaveToExtraUri) {
+ done();
+ }
+ }
+
+ public void done() {
+ if (outputted) {
+ hideSavingProgress();
+ }
+ finish();
}
static {
diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java
index 03a9d8bd5..94259e91d 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -32,6 +32,7 @@ import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
import com.android.gallery3d.filtershow.filters.ImageFilterExposure;
import com.android.gallery3d.filtershow.filters.ImageFilterHue;
+import com.android.gallery3d.filtershow.filters.ImageFilterNegative;
import com.android.gallery3d.filtershow.filters.ImageFilterRedEye;
import com.android.gallery3d.filtershow.filters.ImageFilterSaturated;
import com.android.gallery3d.filtershow.filters.ImageFilterShadows;
@@ -41,8 +42,8 @@ import com.android.gallery3d.filtershow.filters.ImageFilterVibrance;
import com.android.gallery3d.filtershow.filters.ImageFilterVignette;
import com.android.gallery3d.filtershow.filters.ImageFilterWBalance;
import com.android.gallery3d.filtershow.imageshow.ImageCrop;
-import com.android.gallery3d.filtershow.imageshow.ImageGeometry;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
+import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter;
import com.android.gallery3d.filtershow.presets.ImagePreset;
import com.android.gallery3d.filtershow.ui.FramedTextButton;
import com.android.gallery3d.filtershow.ui.ImageCurves;
@@ -57,6 +58,12 @@ public class PanelController implements OnClickListener {
private static int HORIZONTAL_MOVE = 1;
private static final int ANIM_DURATION = 200;
private static final String LOGTAG = "PanelController";
+ private boolean mDisableFilterButtons = false;
+ private boolean mFixedAspect = false;
+
+ public void setFixedAspect(boolean t) {
+ mFixedAspect = t;
+ }
class Panel {
private final View mView;
@@ -158,38 +165,52 @@ public class PanelController implements OnClickListener {
ImageCrop imageCrop = (ImageCrop) mCurrentImage;
switch (itemId) {
case R.id.crop_menu_1to1: {
- button.setText(mContext.getString(R.string.aspect1to1_effect));
+ String t = mContext.getString(R.string.aspect1to1_effect);
+ button.setText(t);
imageCrop.apply(1, 1);
+ imageCrop.setAspectString(t);
break;
}
case R.id.crop_menu_4to3: {
- button.setText(mContext.getString(R.string.aspect4to3_effect));
+ String t = mContext.getString(R.string.aspect4to3_effect);
+ button.setText(t);
imageCrop.apply(4, 3);
+ imageCrop.setAspectString(t);
break;
}
case R.id.crop_menu_3to4: {
- button.setText(mContext.getString(R.string.aspect3to4_effect));
+ String t = mContext.getString(R.string.aspect3to4_effect);
+ button.setText(t);
imageCrop.apply(3, 4);
+ imageCrop.setAspectString(t);
break;
}
case R.id.crop_menu_5to7: {
- button.setText(mContext.getString(R.string.aspect5to7_effect));
+ String t = mContext.getString(R.string.aspect5to7_effect);
+ button.setText(t);
imageCrop.apply(5, 7);
+ imageCrop.setAspectString(t);
break;
}
case R.id.crop_menu_7to5: {
- button.setText(mContext.getString(R.string.aspect7to5_effect));
+ String t = mContext.getString(R.string.aspect7to5_effect);
+ button.setText(t);
imageCrop.apply(7, 5);
+ imageCrop.setAspectString(t);
break;
}
case R.id.crop_menu_none: {
- button.setText(mContext.getString(R.string.aspectNone_effect));
+ String t = mContext.getString(R.string.aspectNone_effect);
+ button.setText(t);
imageCrop.applyClear();
+ imageCrop.setAspectString(t);
break;
}
case R.id.crop_menu_original: {
- button.setText(mContext.getString(R.string.aspectOriginal_effect));
+ String t = mContext.getString(R.string.aspectOriginal_effect);
+ button.setText(t);
imageCrop.applyOriginal();
+ imageCrop.setAspectString(t);
break;
}
}
@@ -287,6 +308,7 @@ public class PanelController implements OnClickListener {
private final HashMap<View, Panel> mPanels = new HashMap<View, Panel>();
private final HashMap<View, ViewType> mViews = new HashMap<View, ViewType>();
+ private final HashMap<String, ImageFilter> mFilters = new HashMap<String, ImageFilter>();
private final Vector<View> mImageViews = new Vector<View>();
private View mCurrentPanel = null;
private View mRowPanel = null;
@@ -320,6 +342,10 @@ public class PanelController implements OnClickListener {
mViews.put(component, new ViewType(component, COMPONENT));
}
+ public void addFilter(ImageFilter filter) {
+ mFilters.put(filter.getName(), filter);
+ }
+
public void addImageView(View view) {
mImageViews.add(view);
ImageShow imageShow = (ImageShow) view;
@@ -332,6 +358,10 @@ public class PanelController implements OnClickListener {
mCurrentImage.resetParameter();
mCurrentImage.select();
}
+ if (mDisableFilterButtons) {
+ mActivity.enableFilterButtons();
+ mDisableFilterButtons = false;
+ }
}
public boolean onBackPressed() {
@@ -343,6 +373,11 @@ public class PanelController implements OnClickListener {
mMasterImage.onItemClick(position);
showPanel(mCurrentPanel);
mCurrentImage.select();
+ if (mDisableFilterButtons) {
+ mActivity.enableFilterButtons();
+ mActivity.resetHistory();
+ mDisableFilterButtons = false;
+ }
return false;
}
@@ -464,60 +499,21 @@ public class PanelController implements OnClickListener {
filter = copy.getFilter(name);
}
- if (filter == null && name.equalsIgnoreCase(
- mCurrentImage.getContext().getString(R.string.curvesRGB))) {
- filter = setImagePreset(new ImageFilterCurves(), name);
- }
- if (filter == null && name.equalsIgnoreCase(
- mCurrentImage.getContext().getString(R.string.tinyplanet))) {
- filter = setImagePreset(new ImageFilterTinyPlanet(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.vignette))) {
- filter = setImagePreset(new ImageFilterVignette(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.sharpness))) {
- filter = setImagePreset(new ImageFilterSharpen(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.contrast))) {
- filter = setImagePreset(new ImageFilterContrast(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.saturation))) {
- filter = setImagePreset(new ImageFilterSaturated(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.bwfilter))) {
- filter = setImagePreset(new ImageFilterBwFilter(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.hue))) {
- filter = setImagePreset(new ImageFilterHue(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.exposure))) {
- filter = setImagePreset(new ImageFilterExposure(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.vibrance))) {
- filter = setImagePreset(new ImageFilterVibrance(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(
- R.string.shadow_recovery))) {
- filter = setImagePreset(new ImageFilterShadows(), name);
- }
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.redeye))) {
- filter = setImagePreset(new ImageFilterRedEye(), name);
+ if (filter == null) {
+ ImageFilter filterInstance = mFilters.get(name);
+ if (filterInstance != null) {
+ try {
+ ImageFilter newFilter = filterInstance.clone();
+ newFilter.reset();
+ filter = setImagePreset(newFilter, name);
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ }
}
- if (filter == null
- && name.equalsIgnoreCase(mCurrentImage.getContext().getString(R.string.wbalance))) {
- filter = setImagePreset(new ImageFilterWBalance(), name);
+ if (filter != null) {
+ mMasterImage.setCurrentFilter(filter);
}
- mMasterImage.setCurrentFilter(filter);
}
private void showCurvesPopupMenu(final ImageCurves curves, final FramedTextButton anchor) {
@@ -574,12 +570,37 @@ public class PanelController implements OnClickListener {
}
mUtilityPanel.hideAspectButtons();
mUtilityPanel.hideCurvesButtons();
+
+ if (view instanceof ImageSmallFilter) {
+ ImageSmallFilter component = (ImageSmallFilter) view;
+ ImageFilter filter = component.getImageFilter();
+ if (filter.getEditingViewId() != 0) {
+ mCurrentImage = showImageView(filter.getEditingViewId());
+ mCurrentImage.setShowControls(filter.showEditingControls());
+ String ename = mCurrentImage.getContext().getString(filter.getTextId());
+ mUtilityPanel.setEffectName(ename);
+ if (view.getId() == R.id.curvesButtonRGB) {
+ // TODO: delegate to the filter / editing view the management of the
+ // panel accessory view
+ mUtilityPanel.showCurvesButtons();
+ }
+ mUtilityPanel.setShowParameter(filter.showParameterValue());
+ ensureFilter(ename);
+ mCurrentImage.select();
+ }
+ return;
+ }
+
switch (view.getId()) {
case R.id.tinyplanetButton: {
mCurrentImage = showImageView(R.id.imageTinyPlanet).setShowControls(true);
String ename = mCurrentImage.getContext().getString(R.string.tinyplanet);
mUtilityPanel.setEffectName(ename);
ensureFilter(ename);
+ if (!mDisableFilterButtons) {
+ mActivity.disableFilterButtons();
+ mDisableFilterButtons = true;
+ }
break;
}
case R.id.straightenButton: {
@@ -593,11 +614,13 @@ public class PanelController implements OnClickListener {
String ename = mCurrentImage.getContext().getString(R.string.crop);
mUtilityPanel.setEffectName(ename);
mUtilityPanel.setShowParameter(false);
- if (mCurrentImage instanceof ImageCrop && mUtilityPanel.firstTimeCropDisplayed){
- ((ImageCrop) mCurrentImage).applyOriginal();
+ if (mCurrentImage instanceof ImageCrop && mUtilityPanel.firstTimeCropDisplayed) {
+ ((ImageCrop) mCurrentImage).clear();
mUtilityPanel.firstTimeCropDisplayed = false;
}
- mUtilityPanel.showAspectButtons();
+ if (!mFixedAspect) {
+ mUtilityPanel.showAspectButtons();
+ }
break;
}
case R.id.rotateButton: {
@@ -613,89 +636,8 @@ public class PanelController implements OnClickListener {
mUtilityPanel.setShowParameter(false);
break;
}
- case R.id.vignetteButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.vignette);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.curvesButtonRGB: {
- ImageCurves curves = (ImageCurves) showImageView(R.id.imageCurves);
- String ename = curves.getContext().getString(R.string.curvesRGB);
- mUtilityPanel.setEffectName(ename);
- mUtilityPanel.setShowParameter(false);
- mUtilityPanel.showCurvesButtons();
- mCurrentImage = curves;
- ensureFilter(ename);
- break;
- }
- case R.id.sharpenButton: {
- mCurrentImage = showImageView(R.id.imageZoom).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.sharpness);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.contrastButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.contrast);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.saturationButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.saturation);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.bwfilterButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.bwfilter);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.wbalanceButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(false);
- String ename = mCurrentImage.getContext().getString(R.string.wbalance);
- mUtilityPanel.setEffectName(ename);
- mUtilityPanel.setShowParameter(false);
- ensureFilter(ename);
- break;
- }
- case R.id.hueButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.hue);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.exposureButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.exposure);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.vibranceButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.vibrance);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
- case R.id.shadowRecoveryButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- String ename = mCurrentImage.getContext().getString(R.string.shadow_recovery);
- mUtilityPanel.setEffectName(ename);
- ensureFilter(ename);
- break;
- }
case R.id.redEyeButton: {
- mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
+ mCurrentImage = showImageView(R.id.imageRedEyes).setShowControls(true);
String ename = mCurrentImage.getContext().getString(R.string.redeye);
mUtilityPanel.setEffectName(ename);
ensureFilter(ename);
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 7874881fa..a1a1ba186 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -18,6 +18,7 @@ package com.android.gallery3d.filtershow.cache;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
@@ -26,6 +27,7 @@ import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.Bitmap.CompressFormat;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
@@ -39,12 +41,15 @@ import com.android.gallery3d.common.Utils;
import com.android.gallery3d.exif.ExifInvalidFormatException;
import com.android.gallery3d.exif.ExifParser;
import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.filtershow.CropExtras;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.HistoryAdapter;
import com.android.gallery3d.filtershow.imageshow.ImageCrop;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.presets.ImagePreset;
+import com.android.gallery3d.filtershow.tools.BitmapTask;
import com.android.gallery3d.filtershow.tools.SaveCopyTask;
+import com.android.gallery3d.util.InterruptableOutputStream;
import com.android.gallery3d.util.XmpUtilHelper;
import java.io.Closeable;
@@ -53,7 +58,9 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.util.Vector;
+import java.util.concurrent.locks.ReentrantLock;
public class ImageLoader {
@@ -72,13 +79,16 @@ public class ImageLoader {
private FilterShowActivity mActivity = null;
- public static final int ORI_NORMAL = ExifInterface.ORIENTATION_NORMAL;
- public static final int ORI_ROTATE_90 = ExifInterface.ORIENTATION_ROTATE_90;
+ public static final String DEFAULT_SAVE_DIRECTORY = "EditedOnlinePhotos";
+ public static final int DEFAULT_COMPRESS_QUALITY = 95;
+
+ public static final int ORI_NORMAL = ExifInterface.ORIENTATION_NORMAL;
+ public static final int ORI_ROTATE_90 = ExifInterface.ORIENTATION_ROTATE_90;
public static final int ORI_ROTATE_180 = ExifInterface.ORIENTATION_ROTATE_180;
public static final int ORI_ROTATE_270 = ExifInterface.ORIENTATION_ROTATE_270;
- public static final int ORI_FLIP_HOR = ExifInterface.ORIENTATION_FLIP_HORIZONTAL;
- public static final int ORI_FLIP_VERT = ExifInterface.ORIENTATION_FLIP_VERTICAL;
- public static final int ORI_TRANSPOSE = ExifInterface.ORIENTATION_TRANSPOSE;
+ public static final int ORI_FLIP_HOR = ExifInterface.ORIENTATION_FLIP_HORIZONTAL;
+ public static final int ORI_FLIP_VERT = ExifInterface.ORIENTATION_FLIP_VERTICAL;
+ public static final int ORI_TRANSPOSE = ExifInterface.ORIENTATION_TRANSPOSE;
public static final int ORI_TRANSVERSE = ExifInterface.ORIENTATION_TRANSVERSE;
private Context mContext = null;
@@ -87,6 +97,8 @@ public class ImageLoader {
private Rect mOriginalBounds = null;
private static int mZoomOrientation = ORI_NORMAL;
+ private ReentrantLock mLoadingLock = new ReentrantLock();
+
public ImageLoader(FilterShowActivity activity, Context context) {
mActivity = activity;
mContext = context;
@@ -102,16 +114,24 @@ public class ImageLoader {
return mActivity;
}
- public void loadBitmap(Uri uri,int size) {
+ public boolean loadBitmap(Uri uri, int size) {
+ mLoadingLock.lock();
mUri = uri;
mOrientation = getOrientation(mContext, uri);
mOriginalBitmapSmall = loadScaledBitmap(uri, 160);
if (mOriginalBitmapSmall == null) {
// Couldn't read the bitmap, let's exit
- mActivity.cannotLoadImage();
+ mLoadingLock.unlock();
+ return false;
}
mOriginalBitmapLarge = loadScaledBitmap(uri, size);
+ if (mOriginalBitmapLarge == null) {
+ mLoadingLock.unlock();
+ return false;
+ }
updateBitmaps();
+ mLoadingLock.unlock();
+ return true;
}
public Uri getUri() {
@@ -134,21 +154,27 @@ public class ImageLoader {
MediaStore.Images.ImageColumns.ORIENTATION
},
null, null, null);
- if (cursor.moveToNext()){
- int ori = cursor.getInt(0);
-
- switch (ori){
- case 0: return ORI_NORMAL;
- case 90: return ORI_ROTATE_90;
- case 270: return ORI_ROTATE_270;
- case 180: return ORI_ROTATE_180;
- default:
- return -1;
- }
- } else{
+ if (cursor.moveToNext()) {
+ int ori = cursor.getInt(0);
+
+ switch (ori) {
+ case 0:
+ return ORI_NORMAL;
+ case 90:
+ return ORI_ROTATE_90;
+ case 270:
+ return ORI_ROTATE_270;
+ case 180:
+ return ORI_ROTATE_180;
+ default:
+ return -1;
+ }
+ } else {
return -1;
}
- } catch (SQLiteException e){
+ } catch (SQLiteException e) {
+ return ExifInterface.ORIENTATION_UNDEFINED;
+ } catch (IllegalArgumentException e) {
return ExifInterface.ORIENTATION_UNDEFINED;
} finally {
Utils.closeSilently(cursor);
@@ -193,46 +219,46 @@ public class ImageLoader {
warnListeners();
}
- public static Bitmap rotateToPortrait(Bitmap bitmap,int ori) {
- Matrix matrix = new Matrix();
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- if (ori == ORI_ROTATE_90 ||
- ori == ORI_ROTATE_270 ||
- ori == ORI_TRANSPOSE||
- ori == ORI_TRANSVERSE) {
- int tmp = w;
- w = h;
- h = tmp;
- }
- switch(ori){
- case ORI_ROTATE_90:
- matrix.setRotate(90,w/2f,h/2f);
- break;
- case ORI_ROTATE_180:
- matrix.setRotate(180,w/2f,h/2f);
- break;
- case ORI_ROTATE_270:
- matrix.setRotate(270,w/2f,h/2f);
- break;
- case ORI_FLIP_HOR:
- matrix.preScale(-1, 1);
- break;
- case ORI_FLIP_VERT:
- matrix.preScale(1, -1);
- break;
- case ORI_TRANSPOSE:
- matrix.setRotate(90,w/2f,h/2f);
- matrix.preScale(1, -1);
- break;
- case ORI_TRANSVERSE:
- matrix.setRotate(270,w/2f,h/2f);
- matrix.preScale(1, -1);
- break;
- case ORI_NORMAL:
- default:
- return bitmap;
- }
+ public static Bitmap rotateToPortrait(Bitmap bitmap, int ori) {
+ Matrix matrix = new Matrix();
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ if (ori == ORI_ROTATE_90 ||
+ ori == ORI_ROTATE_270 ||
+ ori == ORI_TRANSPOSE ||
+ ori == ORI_TRANSVERSE) {
+ int tmp = w;
+ w = h;
+ h = tmp;
+ }
+ switch (ori) {
+ case ORI_ROTATE_90:
+ matrix.setRotate(90, w / 2f, h / 2f);
+ break;
+ case ORI_ROTATE_180:
+ matrix.setRotate(180, w / 2f, h / 2f);
+ break;
+ case ORI_ROTATE_270:
+ matrix.setRotate(270, w / 2f, h / 2f);
+ break;
+ case ORI_FLIP_HOR:
+ matrix.preScale(-1, 1);
+ break;
+ case ORI_FLIP_VERT:
+ matrix.preScale(1, -1);
+ break;
+ case ORI_TRANSPOSE:
+ matrix.setRotate(90, w / 2f, h / 2f);
+ matrix.preScale(1, -1);
+ break;
+ case ORI_TRANSVERSE:
+ matrix.setRotate(270, w / 2f, h / 2f);
+ matrix.preScale(1, -1);
+ break;
+ case ORI_NORMAL:
+ default:
+ return bitmap;
+ }
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
@@ -265,6 +291,7 @@ public class ImageLoader {
}
static final int MAX_BITMAP_DIM = 2048;
+
private Bitmap loadScaledBitmap(Uri uri, int size) {
InputStream is = null;
try {
@@ -327,10 +354,12 @@ public class ImageLoader {
}
public void addListener(ImageShow imageShow) {
+ mLoadingLock.lock();
if (!mListeners.contains(imageShow)) {
mListeners.add(imageShow);
}
mHiresCache.addObserver(imageShow);
+ mLoadingLock.unlock();
}
private void warnListeners() {
@@ -348,10 +377,12 @@ public class ImageLoader {
}
};
- // TODO: this currently does the loading + filtering on the UI thread -- need to
+ // TODO: this currently does the loading + filtering on the UI thread --
+ // need to
// move this to a background thread.
public Bitmap getScaleOneImageForPreset(ImageShow caller, ImagePreset imagePreset, Rect bounds,
boolean force) {
+ mLoadingLock.lock();
Bitmap bmp = mZoomCache.getImage(imagePreset, bounds);
if (force || bmp == null) {
bmp = loadRegionBitmap(mUri, bounds);
@@ -363,19 +394,24 @@ public class ImageLoader {
bmp2 = imagePreset.apply(bmp2);
imagePreset.setScaleFactor(scaleFactor);
mZoomCache.setImage(imagePreset, bounds, bmp2);
+ mLoadingLock.unlock();
return bmp2;
}
}
+ mLoadingLock.unlock();
return bmp;
}
// Caching method
public Bitmap getImageForPreset(ImageShow caller, ImagePreset imagePreset,
boolean hiRes) {
+ mLoadingLock.lock();
if (mOriginalBitmapSmall == null) {
+ mLoadingLock.unlock();
return null;
}
if (mOriginalBitmapLarge == null) {
+ mLoadingLock.unlock();
return null;
}
@@ -396,13 +432,16 @@ public class ImageLoader {
mCache.addObserver(caller);
}
}
+ mLoadingLock.unlock();
return filteredImage;
}
public void resetImageForPreset(ImagePreset imagePreset, ImageShow caller) {
+ mLoadingLock.lock();
mHiresCache.reset(imagePreset);
mCache.reset(imagePreset);
mZoomCache.reset(imagePreset);
+ mLoadingLock.unlock();
}
public void saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity,
@@ -419,6 +458,109 @@ public class ImageLoader {
}).execute(preset);
}
+ public static Bitmap loadMutableBitmap(Context context, Uri sourceUri)
+ throws FileNotFoundException {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ // TODO: on <3.x we need a copy of the bitmap (inMutable doesn't
+ // exist)
+ options.inMutable = true;
+
+ InputStream is = context.getContentResolver().openInputStream(sourceUri);
+ Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
+ int orientation = ImageLoader.getOrientation(context, sourceUri);
+ bitmap = ImageLoader.rotateToPortrait(bitmap, orientation);
+ return bitmap;
+ }
+
+ public void returnFilteredResult(ImagePreset preset,
+ final FilterShowActivity filterShowActivity) {
+ preset.setIsHighQuality(true);
+ preset.setScaleFactor(1.0f);
+
+ BitmapTask.Callbacks<ImagePreset> cb = new BitmapTask.Callbacks<ImagePreset>() {
+
+ @Override
+ public void onComplete(Bitmap result) {
+ filterShowActivity.onFilteredResult(result);
+ }
+
+ @Override
+ public void onCancel() {
+ }
+
+ @Override
+ public Bitmap onExecute(ImagePreset param) {
+ if (param == null) {
+ return null;
+ }
+ try {
+ Bitmap bitmap = param.apply(loadMutableBitmap(mContext, mUri));
+ return bitmap;
+ } catch (FileNotFoundException ex) {
+ Log.w(LOGTAG, "Failed to save image!", ex);
+ return null;
+ }
+ }
+ };
+
+ (new BitmapTask<ImagePreset>(cb)).execute(preset);
+ }
+
+ private String getFileExtension(String requestFormat) {
+ String outputFormat = (requestFormat == null)
+ ? "jpg"
+ : requestFormat;
+ outputFormat = outputFormat.toLowerCase();
+ return (outputFormat.equals("png") || outputFormat.equals("gif"))
+ ? "png" // We don't support gif compression.
+ : "jpg";
+ }
+
+ private CompressFormat convertExtensionToCompressFormat(String extension) {
+ return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
+ }
+
+ public void saveToUri(Bitmap bmap, Uri uri, final String outputFormat,
+ final FilterShowActivity filterShowActivity) {
+
+ OutputStream out = null;
+ try {
+ out = filterShowActivity.getContentResolver().openOutputStream(uri);
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "cannot write output", e);
+ out = null;
+ } finally {
+ if (bmap == null || out == null) {
+ return;
+ }
+ }
+
+ final InterruptableOutputStream ios = new InterruptableOutputStream(out);
+
+ BitmapTask.Callbacks<Bitmap> cb = new BitmapTask.Callbacks<Bitmap>() {
+
+ @Override
+ public void onComplete(Bitmap result) {
+ filterShowActivity.done();
+ }
+
+ @Override
+ public void onCancel() {
+ ios.interrupt();
+ }
+
+ @Override
+ public Bitmap onExecute(Bitmap param) {
+ CompressFormat cf = convertExtensionToCompressFormat(getFileExtension(outputFormat));
+ param.compress(cf, DEFAULT_COMPRESS_QUALITY, ios);
+ Utils.closeSilently(ios);
+ return null;
+ }
+ };
+
+ (new BitmapTask<Bitmap>(cb)).execute(bmap);
+ }
+
public void setAdapter(HistoryAdapter adapter) {
mAdapter = adapter;
}
@@ -479,4 +621,9 @@ public class ImageLoader {
}
}
+ public void addCacheListener(ImageShow imageShow) {
+ mHiresCache.addObserver(imageShow);
+ mCache.addObserver(imageShow);
+ }
+
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index d00c7e31b..b8f0cf84f 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -18,35 +18,64 @@ package com.android.gallery3d.filtershow.filters;
import android.graphics.Bitmap;
+import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.presets.ImagePreset;
public class ImageFilter implements Cloneable {
- protected int mMaxParameter = 100;
- protected int mMinParameter = -100;
+ public static int DEFAULT_MAX_PARAMETER = 100;
+ public static int DEFAULT_MIN_PARAMETER = -100;
+ public static int DEFAULT_INITIAL_PARAMETER = 0;
+
+ protected int mMaxParameter = DEFAULT_MAX_PARAMETER;
+ protected int mMinParameter = DEFAULT_MIN_PARAMETER;
protected int mPreviewParameter = mMaxParameter;
- protected int mDefaultParameter = 0;
- protected int mParameter = 0;
+ protected int mDefaultParameter = DEFAULT_INITIAL_PARAMETER;
+ protected int mParameter = DEFAULT_INITIAL_PARAMETER;
private ImagePreset mImagePreset;
protected String mName = "Original";
private final String LOGTAG = "ImageFilter";
- public static final byte TYPE_BORDER =1;
- public static final byte TYPE_FX = 2;
+ public static final byte TYPE_BORDER = 1;
+ public static final byte TYPE_FX = 2;
public static final byte TYPE_WBALANCE = 3;
public static final byte TYPE_VIGNETTE = 4;
public static final byte TYPE_NORMAL = 5;
public static final byte TYPE_TINYPLANET = 6;
private byte filterType = TYPE_NORMAL;
- public byte getFilterType(){
+ public byte getFilterType() {
return filterType;
}
- protected void setFilterType(byte type){
+ protected void setFilterType(byte type) {
filterType = type;
}
+ public int getButtonId() {
+ return 0;
+ }
+
+ public int getTextId() {
+ return 0;
+ }
+
+ public int getOverlayBitmaps() {
+ return 0;
+ }
+
+ public int getEditingViewId() {
+ return R.id.imageShow;
+ }
+
+ public boolean showEditingControls() {
+ return true;
+ }
+
+ public boolean showParameterValue() {
+ return true;
+ }
+
@Override
public ImageFilter clone() throws CloneNotSupportedException {
ImageFilter filter = (ImageFilter) super.clone();
@@ -61,6 +90,10 @@ public class ImageFilter implements Cloneable {
return filter;
}
+ public void reset() {
+ setParameter(mDefaultParameter);
+ }
+
public boolean isNil() {
if (mParameter == mDefaultParameter) {
return true;
@@ -93,7 +126,7 @@ public class ImageFilter implements Cloneable {
* The maximum allowed value (inclusive)
* @return maximum value allowed as input to this filter
*/
- public int getMaxParameter(){
+ public int getMaxParameter() {
return mMaxParameter;
}
@@ -101,7 +134,7 @@ public class ImageFilter implements Cloneable {
* The parameter value to be used in previews.
* @return parameter value to be used to preview the filter
*/
- public int getPreviewParameter(){
+ public int getPreviewParameter() {
return mPreviewParameter;
}
@@ -109,7 +142,7 @@ public class ImageFilter implements Cloneable {
* The minimum allowed value (inclusive)
* @return minimum value allowed as input to this filter
*/
- public int getMinParameter(){
+ public int getMinParameter() {
return mMinParameter;
}
@@ -117,7 +150,7 @@ public class ImageFilter implements Cloneable {
* Returns the default value returned by this filter.
* @return default value
*/
- public int getDefaultParameter(){
+ public int getDefaultParameter() {
return mDefaultParameter;
}
@@ -130,6 +163,9 @@ public class ImageFilter implements Cloneable {
}
public boolean same(ImageFilter filter) {
+ if (filter == null) {
+ return false;
+ }
if (!filter.getName().equalsIgnoreCase(getName())) {
return false;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBWBlue.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBWBlue.java
deleted file mode 100644
index 45f49164b..000000000
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBWBlue.java
+++ /dev/null
@@ -1,37 +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;
-
-public class ImageFilterBWBlue extends ImageFilter {
-
- public ImageFilterBWBlue() {
- mName = "B&W - Blue";
- }
-
- native protected void nativeApplyFilter(Bitmap bitmap, int w, int h);
-
- @Override
- public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- nativeApplyFilter(bitmap, w, h);
- return bitmap;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBWGreen.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBWGreen.java
deleted file mode 100644
index 8f91c3c82..000000000
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBWGreen.java
+++ /dev/null
@@ -1,37 +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;
-
-public class ImageFilterBWGreen extends ImageFilter {
-
- public ImageFilterBWGreen() {
- mName = "B&W - Green";
- }
-
- native protected void nativeApplyFilter(Bitmap bitmap, int w, int h);
-
- @Override
- public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- nativeApplyFilter(bitmap, w, h);
- return bitmap;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBWRed.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBWRed.java
deleted file mode 100644
index f0c65d71e..000000000
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBWRed.java
+++ /dev/null
@@ -1,37 +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;
-
-public class ImageFilterBWRed extends ImageFilter {
-
- public ImageFilterBWRed() {
- mName = "B&W - Red";
- }
-
- native protected void nativeApplyFilter(Bitmap bitmap, int w, int h);
-
- @Override
- public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- nativeApplyFilter(bitmap, w, h);
- return bitmap;
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
index a310358ce..1d198e45c 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
@@ -51,6 +51,9 @@ public class ImageFilterBorder extends ImageFilter {
if (!isBorderFilter) {
return false;
}
+ if (!(filter instanceof ImageFilterBorder)) {
+ return false;
+ }
ImageFilterBorder borderFilter = (ImageFilterBorder) filter;
if (mNinePatch != borderFilter.mNinePatch) {
return false;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
index 558abe3c3..1bb5c76ac 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
import android.graphics.Color;
@@ -29,6 +31,16 @@ public class ImageFilterBwFilter extends ImageFilter {
}
@Override
+ public int getButtonId() {
+ return R.id.bwfilterButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.bwfilter;
+ }
+
+ @Override
public ImageFilter clone() throws CloneNotSupportedException {
ImageFilterBwFilter filter = (ImageFilterBwFilter) super.clone();
return filter;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
index 0c3bb37ca..70e3d8589 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterContrast extends ImageFilter {
@@ -24,6 +26,16 @@ public class ImageFilterContrast extends ImageFilter {
mName = "Contrast";
}
+ @Override
+ public int getButtonId() {
+ return R.id.contrastButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.contrast;
+ }
+
native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float strength);
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java
index 89641d103..ba49a8fcb 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java
@@ -18,6 +18,7 @@ package com.android.gallery3d.filtershow.filters;
import android.graphics.Bitmap;
+import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.ui.Spline;
public class ImageFilterCurves extends ImageFilter {
@@ -31,6 +32,31 @@ public class ImageFilterCurves extends ImageFilter {
}
@Override
+ public int getButtonId() {
+ return R.id.curvesButtonRGB;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.curvesRGB;
+ }
+
+ @Override
+ public int getOverlayBitmaps() {
+ return R.drawable.filtershow_button_colors_curve;
+ }
+
+ @Override
+ public int getEditingViewId() {
+ return R.id.imageCurves;
+ }
+
+ @Override
+ public boolean showParameterValue() {
+ return false;
+ }
+
+ @Override
public ImageFilter clone() throws CloneNotSupportedException {
ImageFilterCurves filter = (ImageFilterCurves) super.clone();
for (int i = 0; i < 4; i++) {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java
new file mode 100644
index 000000000..fa2293ca7
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java
@@ -0,0 +1,68 @@
+/*
+ * 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 com.android.gallery3d.R;
+
+public class ImageFilterDownsample extends ImageFilter {
+
+ public ImageFilterDownsample() {
+ mName = "Downsample";
+ mMaxParameter = 100;
+ mMinParameter = 5;
+ mPreviewParameter = 10;
+ mDefaultParameter = 50;
+ mParameter = 50;
+ }
+
+ @Override
+ public int getButtonId() {
+ return R.id.downsampleButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.downsample;
+ }
+
+ @Override
+ public boolean isNil() {
+ return false;
+ }
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ int p = mParameter;
+ if (p > 0 && p < 100) {
+ int newWidth = w * p / 100;
+ int newHeight = h * p / 100;
+ if (newWidth <= 0 || newHeight <= 0) {
+ return bitmap;
+ }
+ Bitmap ret = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
+ if (ret != bitmap) {
+ bitmap.recycle();
+ }
+ return ret;
+ }
+ return bitmap;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBW.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
index f4a7717f9..9eda64874 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBW.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
@@ -18,20 +18,39 @@ package com.android.gallery3d.filtershow.filters;
import android.graphics.Bitmap;
-public class ImageFilterBW extends ImageFilter {
+import com.android.gallery3d.R;
- public ImageFilterBW() {
- mName = "Black & White";
+public class ImageFilterEdge extends ImageFilter {
+
+ public ImageFilterEdge() {
+ mName = "Edge";
+ mPreviewParameter = 0;
}
- native protected void nativeApplyFilter(Bitmap bitmap, int w, int h);
+ native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float p);
+
+ @Override
+ public int getButtonId() {
+ return R.id.edgeButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.edge;
+ }
+
+ @Override
+ public boolean isNil() {
+ return false;
+ }
@Override
public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
- nativeApplyFilter(bitmap, w, h);
+ float p = mParameter + 101;
+ p = (float) p / 100;
+ nativeApplyFilter(bitmap, w, h, p);
return bitmap;
}
-
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
index e38dc8eb5..63f860171 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterExposure extends ImageFilter {
@@ -24,6 +26,16 @@ public class ImageFilterExposure extends ImageFilter {
mName = "Exposure";
}
+ @Override
+ public int getButtonId() {
+ return R.id.exposureButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.exposure;
+ }
+
native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float bright);
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
index bdcb0ea4e..33ecc8ab9 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
@@ -23,6 +23,7 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
+import com.android.gallery3d.filtershow.CropExtras;
import com.android.gallery3d.filtershow.imageshow.GeometryMath;
import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
@@ -69,22 +70,56 @@ public class ImageFilterGeometry extends ImageFilter {
// 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?)
+
+ CropExtras extras = mGeometry.getCropExtras();
+ boolean useExtras = mGeometry.getUseCropExtrasFlag();
+ int outputX = 0;
+ int outputY = 0;
+ boolean s = false;
+ if (extras != null && useExtras){
+ outputX = extras.getOutputX();
+ outputY = extras.getOutputY();
+ s = extras.getScaleUp();
+ }
+
+
Rect cropBounds = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
RectF crop = mGeometry.getCropBounds(bitmap);
if (crop.width() > 0 && crop.height() > 0)
- crop.roundOut(cropBounds);
- Bitmap temp = null;
- if (mGeometry.hasSwitchedWidthHeight()) {
- temp = Bitmap.createBitmap(cropBounds.height(), cropBounds.width(), mConfig);
- } else {
- temp = Bitmap.createBitmap(cropBounds.width(), cropBounds.height(), mConfig);
+ cropBounds = GeometryMath.roundNearest(crop);
+
+ int width = cropBounds.width();
+ int height = cropBounds.height();
+
+ if (mGeometry.hasSwitchedWidthHeight()){
+ int temp = width;
+ width = height;
+ height = temp;
}
+
+ if(outputX <= 0 || outputY <= 0){
+ outputX = width;
+ outputY = height;
+ }
+
+ float scaleX = 1;
+ float scaleY = 1;
+ if (s){
+ scaleX = (float) outputX / width;
+ scaleY = (float) outputY / height;
+ }
+
+ Bitmap temp = null;
+ temp = Bitmap.createBitmap(outputX, outputY, mConfig);
+
float[] displayCenter = {
temp.getWidth() / 2f, temp.getHeight() / 2f
};
Matrix m1 = mGeometry.buildTotalXform(bitmap.getWidth(), bitmap.getHeight(), displayCenter);
+ m1.postScale(scaleX, scaleY, displayCenter[0], displayCenter[1]);
+
Canvas canvas = new Canvas(temp);
Paint paint = new Paint();
paint.setAntiAlias(true);
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
index 279718edb..e2ea388dc 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterHue extends ImageFilter {
@@ -29,6 +31,16 @@ public class ImageFilterHue extends ImageFilter {
}
@Override
+ public int getButtonId() {
+ return R.id.hueButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.hue;
+ }
+
+ @Override
public ImageFilter clone() throws CloneNotSupportedException {
ImageFilterHue filter = (ImageFilterHue) super.clone();
filter.cmatrix = new ColorSpaceMatrix(cmatrix);
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
new file mode 100644
index 000000000..f03baca39
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
@@ -0,0 +1,94 @@
+/*
+ * 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.text.format.Time;
+
+import com.android.gallery3d.R;
+
+public class ImageFilterKMeans extends ImageFilter {
+ private int mSeed = 0;
+
+ public ImageFilterKMeans() {
+ mName = "KMeans";
+ mMaxParameter = 20;
+ mMinParameter = 2;
+ mPreviewParameter = 4;
+ mDefaultParameter = 4;
+ mParameter = 4;
+
+ // set random seed for session
+ Time t = new Time();
+ t.setToNow();
+ mSeed = (int) t.toMillis(false);
+ }
+
+ native protected void nativeApplyFilter(Bitmap bitmap, int width, int height,
+ Bitmap large_ds_bm, int lwidth, int lheight, Bitmap small_ds_bm,
+ int swidth, int sheight, int p, int seed);
+
+ @Override
+ public int getButtonId() {
+ return R.id.kmeansButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.kmeans;
+ }
+
+ @Override
+ public boolean isNil() {
+ return false;
+ }
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+
+ Bitmap large_bm_ds = bitmap;
+ Bitmap small_bm_ds = bitmap;
+
+ // find width/height for larger downsampled bitmap
+ int lw = w;
+ int lh = h;
+ while (lw > 256 && lh > 256) {
+ lw /= 2;
+ lh /= 2;
+ }
+ if (lw != w) {
+ large_bm_ds = Bitmap.createScaledBitmap(bitmap, lw, lh, true);
+ }
+
+ // find width/height for smaller downsampled bitmap
+ int sw = lw;
+ int sh = lh;
+ while (sw > 64 && sh > 64) {
+ sw /= 2;
+ sh /= 2;
+ }
+ if (sw != lw) {
+ small_bm_ds = Bitmap.createScaledBitmap(large_bm_ds, sw, sh, true);
+ }
+
+ int p = Math.max(mParameter, mMinParameter) % (mMaxParameter + 1);
+ nativeApplyFilter(bitmap, w, h, large_bm_ds, lw, lh, small_bm_ds, sw, sh, p, mSeed);
+ return bitmap;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
new file mode 100644
index 000000000..04fd1e42e
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
@@ -0,0 +1,47 @@
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+
+import com.android.gallery3d.R;
+
+public class ImageFilterNegative extends ImageFilter {
+
+ public ImageFilterNegative() {
+ mName = "Negative";
+ }
+
+ @Override
+ public int getButtonId() {
+ return R.id.negativeButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.negative;
+ }
+
+ @Override
+ public boolean isNil() {
+ return false;
+ }
+
+ @Override
+ public boolean showEditingControls() {
+ return false;
+ }
+
+ @Override
+ public boolean showParameterValue() {
+ return false;
+ }
+
+ native protected void nativeApplyFilter(Bitmap bitmap, int w, int h);
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ nativeApplyFilter(bitmap, w, h);
+ return bitmap;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
index 3d6954691..ade3cb26b 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
@@ -56,6 +56,9 @@ public class ImageFilterParametricBorder extends ImageFilter {
if (!isBorderFilter) {
return false;
}
+ if (!(filter instanceof ImageFilterParametricBorder)) {
+ return false;
+ }
ImageFilterParametricBorder borderFilter = (ImageFilterParametricBorder) filter;
if (borderFilter.mBorderColor != mBorderColor) {
return false;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
index c77de330f..9ae6f511e 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
@@ -17,40 +17,167 @@
package com.android.gallery3d.filtershow.filters;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.RectF;
-public class ImageFilterRedEye extends ImageFilter {
- private static final String TAG = "ImageFilterRedEye";
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
+
+import java.util.Vector;
+public class ImageFilterRedEye extends ImageFilter {
+ private static final String LOGTAG = "ImageFilterRedEye";
+ private Vector<RedEyeCandidate> mCandidates = null;
public ImageFilterRedEye() {
- mName = "Redeye";
+ mName = "Red Eye";
+ }
+ @Override
+ public int getButtonId() {
+ return R.id.redEyeButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.redeye;
+ }
+
+ @Override
+ public int getEditingViewId() {
+ return R.id.imageRedEyes;
}
@Override
public ImageFilter clone() throws CloneNotSupportedException {
ImageFilterRedEye filter = (ImageFilterRedEye) super.clone();
-
+ if (mCandidates != null) {
+ int size = mCandidates.size();
+ filter.mCandidates = new Vector<RedEyeCandidate>();
+ for (int i = 0; i < size; i++) {
+ filter.mCandidates.add(new RedEyeCandidate(mCandidates.elementAt(i)));
+ }
+ }
return filter;
}
- native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, short []matrix);
+ @Override
+ public boolean isNil() {
+ if (mCandidates != null && mCandidates.size() > 0) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean same(ImageFilter filter) {
+ boolean isRedEyeFilter = super.same(filter);
+ if (!isRedEyeFilter) {
+ return false;
+ }
+ ImageFilterRedEye redEyeFilter = (ImageFilterRedEye) filter;
+ if (redEyeFilter.mCandidates == null && mCandidates == null) {
+ return true;
+ }
+ if (redEyeFilter.mCandidates == null || mCandidates == null) {
+ return false;
+ }
+ if (redEyeFilter.mCandidates.size() != mCandidates.size()) {
+ return false;
+ }
+ int size = mCandidates.size();
+ for (int i = 0; i < size; i++) {
+ RedEyeCandidate c1 = mCandidates.elementAt(i);
+ RedEyeCandidate c2 = redEyeFilter.mCandidates.elementAt(i);
+ if (!c1.equals(c2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public Vector<RedEyeCandidate> getCandidates() {
+ if (mCandidates == null) {
+ mCandidates = new Vector<RedEyeCandidate>();
+ }
+ return mCandidates;
+ }
+
+ public void addRect(RectF rect, RectF bounds) {
+ if (mCandidates == null) {
+ mCandidates = new Vector<RedEyeCandidate>();
+ }
+ Vector<RedEyeCandidate> intersects = new Vector<RedEyeCandidate>();
+ for (int i = 0; i < mCandidates.size(); i++) {
+ RedEyeCandidate r = mCandidates.elementAt(i);
+ if (r.intersect(rect)) {
+ intersects.add(r);
+ }
+ }
+ for (int i = 0; i < intersects.size(); i++) {
+ RedEyeCandidate r = intersects.elementAt(i);
+ rect.union(r.mRect);
+ bounds.union(r.mBounds);
+ mCandidates.remove(r);
+ }
+ mCandidates.add(new RedEyeCandidate(rect, bounds));
+ }
+
+ public void clear() {
+ if (mCandidates == null) {
+ mCandidates = new Vector<RedEyeCandidate>();
+ }
+ mCandidates.clear();
+ }
+
+ native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, short[] matrix);
@Override
public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
- float p = mParameter;
- float value = p;
- int box = Math.min(w, h);
- int sizex = Math.min((int)((p+100)*box/400),w/2);
- int sizey = Math.min((int)((p+100)*box/800),h/2);
-
- short [] rect = new short[]{
- (short) (w/2-sizex),(short) (w/2-sizey),
- (short) (2*sizex),(short) (2*sizey)};
+ short[] rect = new short[4];
- nativeApplyFilter(bitmap, w, h, rect);
+ if (mCandidates != null && mCandidates.size() > 0) {
+ for (int i = 0; i < mCandidates.size(); i++) {
+ RectF r = new RectF(mCandidates.elementAt(i).mRect);
+ GeometryMetadata geo = getImagePreset().mGeoData;
+ Matrix originalToScreen = geo.getOriginalToScreen(true,
+ getImagePreset().getImageLoader().getOriginalBounds().width(),
+ getImagePreset().getImageLoader().getOriginalBounds().height(),
+ w, h);
+ originalToScreen.mapRect(r);
+ if (r.left < 0) {
+ r.left = 0;
+ }
+ if (r.left > w) {
+ r.left = w;
+ }
+ if (r.top < 0) {
+ r.top = 0;
+ }
+ if (r.top > h) {
+ r.top = h;
+ }
+ if (r.right < 0) {
+ r.right = 0;
+ }
+ if (r.right > w) {
+ r.right = w;
+ }
+ if (r.bottom < 0) {
+ r.bottom = 0;
+ }
+ if (r.bottom > h) {
+ r.bottom = h;
+ }
+ rect[0] = (short) r.left;
+ rect[1] = (short) r.top;
+ rect[2] = (short) r.width();
+ rect[3] = (short) r.height();
+ nativeApplyFilter(bitmap, w, h, rect);
+ }
+ }
return bitmap;
}
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
index 1d3459195..129165b3e 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterSaturated extends ImageFilter {
@@ -24,6 +26,16 @@ public class ImageFilterSaturated extends ImageFilter {
mName = "Saturated";
}
+ @Override
+ public int getButtonId() {
+ return R.id.saturationButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.saturation;
+ }
+
native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float saturation);
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
index 4e6b848ae..de8fcd5ea 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterShadows extends ImageFilter {
@@ -26,6 +28,16 @@ public class ImageFilterShadows extends ImageFilter {
}
@Override
+ public int getButtonId() {
+ return R.id.shadowRecoveryButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.shadow_recovery;
+ }
+
+ @Override
public ImageFilter clone() throws CloneNotSupportedException {
ImageFilterShadows filter = (ImageFilterShadows) super.clone();
return filter;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
index a355539c2..1951b9b9e 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
@@ -28,6 +28,26 @@ public class ImageFilterSharpen extends ImageFilterRS {
}
@Override
+ public int getButtonId() {
+ return R.id.sharpenButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.sharpness;
+ }
+
+ @Override
+ public int getOverlayBitmaps() {
+ return R.drawable.filtershow_button_colors_sharpen;
+ }
+
+ @Override
+ public int getEditingViewId() {
+ return R.id.imageZoom;
+ }
+
+ @Override
public void createFilter(android.content.res.Resources res, float scaleFactor,
boolean highQuality) {
int w = mInPixelsAllocation.getType().getX();
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java
index 423e55828..36bd62630 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java
@@ -22,6 +22,8 @@ import android.graphics.RectF;
import com.adobe.xmp.XMPException;
import com.adobe.xmp.XMPMeta;
+import com.android.gallery3d.R;
+import com.android.gallery3d.app.Log;
import com.android.gallery3d.filtershow.presets.ImagePreset;
/**
@@ -58,6 +60,16 @@ public class ImageFilterTinyPlanet extends ImageFilter {
mAngle = 0;
}
+ @Override
+ public int getButtonId() {
+ return R.id.tinyplanetButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.tinyplanet;
+ }
+
public void setAngle(float angle) {
mAngle = angle;
}
@@ -90,8 +102,17 @@ public class ImageFilterTinyPlanet extends ImageFilter {
}
}
- Bitmap mBitmapOut = Bitmap.createBitmap(
- outputSize, outputSize, Bitmap.Config.ARGB_8888);
+ Bitmap mBitmapOut = null;
+ while (mBitmapOut == null) {
+ try {
+ mBitmapOut = Bitmap.createBitmap(
+ outputSize, outputSize, Bitmap.Config.ARGB_8888);
+ } catch (java.lang.OutOfMemoryError e) {
+ System.gc();
+ outputSize /= 2;
+ Log.v(TAG, "No memory to create Full Tiny Planet create half");
+ }
+ }
nativeApplyFilter(bitmapIn, bitmapIn.getWidth(), bitmapIn.getHeight(), mBitmapOut,
outputSize, mParameter / 100f, mAngle);
return mBitmapOut;
@@ -112,10 +133,19 @@ public class ImageFilterTinyPlanet extends ImageFilter {
// Make sure the intermediate image has the similar size to the
// input.
+ Bitmap paddedBitmap = null;
float scale = intermediateWidth / (float) fullPanoWidth;
- Bitmap paddedBitmap = Bitmap.createBitmap(
+ while (paddedBitmap == null) {
+ try {
+ paddedBitmap = Bitmap.createBitmap(
(int) (fullPanoWidth * scale), (int) (fullPanoHeight * scale),
Bitmap.Config.ARGB_8888);
+ } catch (java.lang.OutOfMemoryError e) {
+ System.gc();
+ scale /= 2;
+ Log.v(TAG, "No memory to create Full Tiny Planet create half");
+ }
+ }
Canvas paddedCanvas = new Canvas(paddedBitmap);
int right = left + croppedAreaWidth;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
index 34f8b245e..7720d0490 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterVibrance extends ImageFilter {
@@ -24,6 +26,16 @@ public class ImageFilterVibrance extends ImageFilter {
mName = "Vibrance";
}
+ @Override
+ public int getButtonId() {
+ return R.id.vibranceButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.vibrance;
+ }
+
native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float bright);
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
index 7a471e5b9..3c904fa6c 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterVignette extends ImageFilter {
@@ -25,6 +27,16 @@ public class ImageFilterVignette extends ImageFilter {
mName = "Vignette";
}
+ @Override
+ public int getButtonId() {
+ return R.id.vignetteButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.vignette;
+ }
+
native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float strength);
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
index b00b867b3..8665dc54c 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
@@ -16,6 +16,8 @@
package com.android.gallery3d.filtershow.filters;
+import com.android.gallery3d.R;
+
import android.graphics.Bitmap;
public class ImageFilterWBalance extends ImageFilter {
@@ -26,13 +28,32 @@ public class ImageFilterWBalance extends ImageFilter {
mName = "WBalance";
}
+ @Override
+ public int getButtonId() {
+ return R.id.wbalanceButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.wbalance;
+ }
+
+ public boolean showEditingControls() {
+ return false;
+ }
+
native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, int locX, int locY);
@Override
public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
- nativeApplyFilter(bitmap, w, h, -1,-1);
+ nativeApplyFilter(bitmap, w, h, -1, -1);
return bitmap;
}
+
+ @Override
+ public boolean isNil() {
+ return false;
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java b/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java
new file mode 100644
index 000000000..58d3afa3b
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java
@@ -0,0 +1,50 @@
+/*
+ * 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.RectF;
+
+public class RedEyeCandidate {
+ RectF mRect = new RectF();
+ RectF mBounds = new RectF();
+
+ public RedEyeCandidate(RedEyeCandidate candidate) {
+ mRect.set(candidate.mRect);
+ mBounds.set(candidate.mBounds);
+ }
+
+ public RedEyeCandidate(RectF rect, RectF bounds) {
+ mRect.set(rect);
+ mBounds.set(bounds);
+ }
+
+ public boolean equals(RedEyeCandidate candidate) {
+ if (candidate.mRect.equals(mRect)
+ && candidate.mBounds.equals(mBounds)) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean intersect(RectF rect) {
+ return mRect.intersect(rect);
+ }
+
+ public RectF getRect() {
+ return mRect;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java b/src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java
new file mode 100644
index 000000000..e94d1ed9e
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/BoundedRect.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.gallery3d.filtershow.imageshow;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+
+import java.util.Arrays;
+
+/**
+ * Maintains invariant that inner rectangle is constrained to be within the
+ * outer, rotated rectangle.
+ */
+public class BoundedRect {
+ private float rot;
+ private RectF outer;
+ private RectF inner;
+ private float[] innerRotated;
+
+ public BoundedRect() {
+ rot = 0;
+ outer = new RectF();
+ inner = new RectF();
+ innerRotated = new float[8];
+ }
+
+ public BoundedRect(float rotation, RectF outerRect, RectF innerRect) {
+ rot = rotation;
+ outer = new RectF(outerRect);
+ inner = new RectF(innerRect);
+ innerRotated = CropMath.getCornersFromRect(inner);
+ rotateInner();
+ if (!isConstrained())
+ reconstrain();
+ }
+
+ /**
+ * Sets inner, and re-constrains it to fit within the rotated bounding rect.
+ */
+ public void setInner(RectF newInner) {
+ if (inner.equals(newInner))
+ return;
+ inner = newInner;
+ innerRotated = CropMath.getCornersFromRect(inner);
+ rotateInner();
+ if (!isConstrained())
+ reconstrain();
+ }
+
+ /**
+ * Sets rotation, and re-constrains inner to fit within the rotated bounding rect.
+ */
+ public void setRotation(float rotation) {
+ if (rotation == rot)
+ return;
+ rot = rotation;
+ innerRotated = CropMath.getCornersFromRect(inner);
+ rotateInner();
+ if (!isConstrained())
+ reconstrain();
+ }
+
+ public RectF getInner() {
+ return new RectF(inner);
+ }
+
+ /**
+ * Tries to move the inner rectangle by (dx, dy). If this would cause it to leave
+ * the bounding rectangle, snaps the inner rectangle to the edge of the bounding
+ * rectangle.
+ */
+ public void moveInner(float dx, float dy) {
+ Matrix m0 = getInverseRotMatrix();
+
+ RectF translatedInner = new RectF(inner);
+ translatedInner.offset(dx, dy);
+
+ float[] translatedInnerCorners = CropMath.getCornersFromRect(translatedInner);
+ float[] outerCorners = CropMath.getCornersFromRect(outer);
+
+ m0.mapPoints(translatedInnerCorners);
+ float[] correction = {
+ 0, 0
+ };
+
+ // find correction vectors for corners that have moved out of bounds
+ for (int i = 0; i < translatedInnerCorners.length; i += 2) {
+ float correctedInnerX = translatedInnerCorners[i] + correction[0];
+ float correctedInnerY = translatedInnerCorners[i + 1] + correction[1];
+ if (!CropMath.inclusiveContains(outer, correctedInnerX, correctedInnerY)) {
+ float[] badCorner = {
+ correctedInnerX, correctedInnerY
+ };
+ float[] nearestSide = CropMath.closestSide(badCorner, outerCorners);
+ float[] correctionVec =
+ GeometryMath.shortestVectorFromPointToLine(badCorner, nearestSide);
+ correction[0] += correctionVec[0];
+ correction[1] += correctionVec[1];
+ }
+ }
+
+ for (int i = 0; i < translatedInnerCorners.length; i += 2) {
+ float correctedInnerX = translatedInnerCorners[i] + correction[0];
+ float correctedInnerY = translatedInnerCorners[i + 1] + correction[1];
+ if (!CropMath.inclusiveContains(outer, correctedInnerX, correctedInnerY)) {
+ float[] correctionVec = {
+ correctedInnerX, correctedInnerY
+ };
+ CropMath.getEdgePoints(outer, correctionVec);
+ correctionVec[0] -= correctedInnerX;
+ correctionVec[1] -= correctedInnerY;
+ correction[0] += correctionVec[0];
+ correction[1] += correctionVec[1];
+ }
+ }
+
+ // Set correction
+ for (int i = 0; i < translatedInnerCorners.length; i += 2) {
+ float correctedInnerX = translatedInnerCorners[i] + correction[0];
+ float correctedInnerY = translatedInnerCorners[i + 1] + correction[1];
+ // update translated corners with correction vectors
+ translatedInnerCorners[i] = correctedInnerX;
+ translatedInnerCorners[i + 1] = correctedInnerY;
+ }
+
+ innerRotated = translatedInnerCorners;
+ // reconstrain to update inner
+ reconstrain();
+ }
+
+ /**
+ * Attempts to resize the inner rectangle. If this would cause it to leave
+ * the bounding rect, clips the inner rectangle to fit.
+ */
+ public void resizeInner(RectF newInner) {
+ Matrix m = getRotMatrix();
+ Matrix m0 = getInverseRotMatrix();
+
+ float[] outerCorners = CropMath.getCornersFromRect(outer);
+ m.mapPoints(outerCorners);
+ float[] oldInnerCorners = CropMath.getCornersFromRect(inner);
+ float[] newInnerCorners = CropMath.getCornersFromRect(newInner);
+ RectF ret = new RectF(newInner);
+
+ for (int i = 0; i < newInnerCorners.length; i += 2) {
+ float[] c = {
+ newInnerCorners[i], newInnerCorners[i + 1]
+ };
+ float[] c0 = Arrays.copyOf(c, 2);
+ m0.mapPoints(c0);
+ if (!CropMath.inclusiveContains(outer, c0[0], c0[1])) {
+ float[] outerSide = CropMath.closestSide(c, outerCorners);
+ float[] pathOfCorner = {
+ newInnerCorners[i], newInnerCorners[i + 1],
+ oldInnerCorners[i], oldInnerCorners[i + 1]
+ };
+ float[] p = GeometryMath.lineIntersect(pathOfCorner, outerSide);
+ if (p == null) {
+ // lines are parallel or not well defined, so don't resize
+ p = new float[2];
+ p[0] = oldInnerCorners[i];
+ p[1] = oldInnerCorners[i + 1];
+ }
+ // relies on corners being in same order as method
+ // getCornersFromRect
+ switch (i) {
+ case 0:
+ case 1:
+ ret.left = (p[0] > ret.left) ? p[0] : ret.left;
+ ret.top = (p[1] > ret.top) ? p[1] : ret.top;
+ break;
+ case 2:
+ case 3:
+ ret.right = (p[0] < ret.right) ? p[0] : ret.right;
+ ret.top = (p[1] > ret.top) ? p[1] : ret.top;
+ break;
+ case 4:
+ case 5:
+ ret.right = (p[0] < ret.right) ? p[0] : ret.right;
+ ret.bottom = (p[1] < ret.bottom) ? p[1] : ret.bottom;
+ break;
+ case 6:
+ case 7:
+ ret.left = (p[0] > ret.left) ? p[0] : ret.left;
+ ret.bottom = (p[1] < ret.bottom) ? p[1] : ret.bottom;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ float[] retCorners = CropMath.getCornersFromRect(ret);
+ m0.mapPoints(retCorners);
+ innerRotated = retCorners;
+ // reconstrain to update inner
+ reconstrain();
+ }
+
+ /**
+ * Attempts to resize the inner rectangle. If this would cause it to leave
+ * the bounding rect, clips the inner rectangle to fit while maintaining
+ * aspect ratio.
+ */
+ public void fixedAspectResizeInner(RectF newInner) {
+ Matrix m = getRotMatrix();
+ Matrix m0 = getInverseRotMatrix();
+
+ float aspectW = inner.width();
+ float aspectH = inner.height();
+ float aspRatio = aspectW / aspectH;
+ float[] corners = CropMath.getCornersFromRect(outer);
+
+ m.mapPoints(corners);
+ float[] oldInnerCorners = CropMath.getCornersFromRect(inner);
+ float[] newInnerCorners = CropMath.getCornersFromRect(newInner);
+
+ // find fixed corner
+ int fixed = -1;
+ if (inner.top == newInner.top) {
+ if (inner.left == newInner.left)
+ fixed = 0; // top left
+ else if (inner.right == newInner.right)
+ fixed = 2; // top right
+ } else if (inner.bottom == newInner.bottom) {
+ if (inner.right == newInner.right)
+ fixed = 4; // bottom right
+ else if (inner.left == newInner.left)
+ fixed = 6; // bottom left
+ }
+ // no fixed corner, return without update
+ if (fixed == -1)
+ return;
+ float widthSoFar = newInner.width();
+ int moved = -1;
+ for (int i = 0; i < newInnerCorners.length; i += 2) {
+ float[] c = {
+ newInnerCorners[i], newInnerCorners[i + 1]
+ };
+ float[] c0 = Arrays.copyOf(c, 2);
+ m0.mapPoints(c0);
+ if (!CropMath.inclusiveContains(outer, c0[0], c0[1])) {
+ moved = i;
+ if (moved == fixed)
+ continue;
+ float[] l2 = CropMath.closestSide(c, corners);
+ float[] l1 = {
+ newInnerCorners[i], newInnerCorners[i + 1],
+ oldInnerCorners[i], oldInnerCorners[i + 1]
+ };
+ float[] p = GeometryMath.lineIntersect(l1, l2);
+ if (p == null) {
+ // lines are parallel or not well defined, so set to old
+ // corner
+ p = new float[2];
+ p[0] = oldInnerCorners[i];
+ p[1] = oldInnerCorners[i + 1];
+ }
+ // relies on corners being in same order as method
+ // getCornersFromRect
+ float fixed_x = oldInnerCorners[fixed];
+ float fixed_y = oldInnerCorners[fixed + 1];
+ float newWidth = Math.abs(fixed_x - p[0]);
+ float newHeight = Math.abs(fixed_y - p[1]);
+ newWidth = Math.max(newWidth, aspRatio * newHeight);
+ if (newWidth < widthSoFar)
+ widthSoFar = newWidth;
+ }
+ }
+
+ float heightSoFar = widthSoFar / aspRatio;
+ RectF ret = new RectF(inner);
+ if (fixed == 0) {
+ ret.right = ret.left + widthSoFar;
+ ret.bottom = ret.top + heightSoFar;
+ } else if (fixed == 2) {
+ ret.left = ret.right - widthSoFar;
+ ret.bottom = ret.top + heightSoFar;
+ } else if (fixed == 4) {
+ ret.left = ret.right - widthSoFar;
+ ret.top = ret.bottom - heightSoFar;
+ } else if (fixed == 6) {
+ ret.right = ret.left + widthSoFar;
+ ret.top = ret.bottom - heightSoFar;
+ }
+ float[] retCorners = CropMath.getCornersFromRect(ret);
+ m0.mapPoints(retCorners);
+ innerRotated = retCorners;
+ // reconstrain to update inner
+ reconstrain();
+ }
+
+ // internal methods
+
+ private boolean isConstrained() {
+ for (int i = 0; i < 8; i += 2) {
+ if (!CropMath.inclusiveContains(outer, innerRotated[i], innerRotated[i + 1]))
+ return false;
+ }
+ return true;
+ }
+
+ private void reconstrain() {
+ // innerRotated has been changed to have incorrect values
+ CropMath.getEdgePoints(outer, innerRotated);
+ Matrix m = getRotMatrix();
+ float[] unrotated = Arrays.copyOf(innerRotated, 8);
+ m.mapPoints(unrotated);
+ inner = CropMath.trapToRect(unrotated);
+ }
+
+ private void rotateInner() {
+ Matrix m = getInverseRotMatrix();
+ m.mapPoints(innerRotated);
+ }
+
+ private Matrix getRotMatrix() {
+ Matrix m = new Matrix();
+ m.setRotate(rot, outer.centerX(), outer.centerY());
+ return m;
+ }
+
+ private Matrix getInverseRotMatrix() {
+ Matrix m = new Matrix();
+ m.setRotate(-rot, outer.centerX(), outer.centerY());
+ return m;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/CropMath.java b/src/com/android/gallery3d/filtershow/imageshow/CropMath.java
new file mode 100644
index 000000000..9037ca043
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/CropMath.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.imageshow;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+
+import java.util.Arrays;
+
+public class CropMath {
+
+ /**
+ * Gets a float array of the 2D coordinates representing a rectangles
+ * corners.
+ * The order of the corners in the float array is:
+ * 0------->1
+ * ^ |
+ * | v
+ * 3<-------2
+ *
+ * @param r the rectangle to get the corners of
+ * @return the float array of corners (8 floats)
+ */
+
+ public static float[] getCornersFromRect(RectF r) {
+ float[] corners = {
+ r.left, r.top,
+ r.right, r.top,
+ r.right, r.bottom,
+ r.left, r.bottom
+ };
+ return corners;
+ }
+
+ /**
+ * Returns true iff point (x, y) is within or on the rectangle's bounds.
+ * RectF's "contains" function treats points on the bottom and right bound
+ * as not being contained.
+ *
+ * @param r the rectangle
+ * @param x the x value of the point
+ * @param y the y value of the point
+ * @return
+ */
+ public static boolean inclusiveContains(RectF r, float x, float y) {
+ return !(x > r.right || x < r.left || y > r.bottom || y < r.top);
+ }
+
+ /**
+ * Takes an array of 2D coordinates representing corners and returns the
+ * smallest rectangle containing those coordinates.
+ *
+ * @param array array of 2D coordinates
+ * @return smallest rectangle containing coordinates
+ */
+ public static RectF trapToRect(float[] array) {
+ RectF r = new RectF(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY,
+ Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
+ for (int i = 1; i < array.length; i += 2) {
+ float x = array[i - 1];
+ float y = array[i];
+ r.left = (x < r.left) ? x : r.left;
+ r.top = (y < r.top) ? y : r.top;
+ r.right = (x > r.right) ? x : r.right;
+ r.bottom = (y > r.bottom) ? y : r.bottom;
+ }
+ r.sort();
+ return r;
+ }
+
+ /**
+ * If edge point [x, y] in array [x0, y0, x1, y1, ...] is outside of the
+ * image bound rectangle, clamps it to the edge of the rectangle.
+ *
+ * @param imageBound the rectangle to clamp edge points to.
+ * @param array an array of points to clamp to the rectangle, gets set to
+ * the clamped values.
+ */
+ public static void getEdgePoints(RectF imageBound, float[] array) {
+ if (array.length < 2)
+ return;
+ for (int x = 0; x < array.length; x += 2) {
+ array[x] = GeometryMath.clamp(array[x], imageBound.left, imageBound.right);
+ array[x + 1] = GeometryMath.clamp(array[x + 1], imageBound.top, imageBound.bottom);
+ }
+ }
+
+ /**
+ * Takes a point and the corners of a rectangle and returns the two corners
+ * representing the side of the rectangle closest to the point.
+ *
+ * @param point the point which is being checked
+ * @param corners the corners of the rectangle
+ * @return two corners representing the side of the rectangle
+ */
+ public static float[] closestSide(float[] point, float[] corners) {
+ int len = corners.length;
+ float oldMag = Float.POSITIVE_INFINITY;
+ float[] bestLine = null;
+ for (int i = 0; i < len; i += 2) {
+ float[] line = {
+ corners[i], corners[(i + 1) % len],
+ corners[(i + 2) % len], corners[(i + 3) % len]
+ };
+ float mag = GeometryMath.vectorLength(
+ GeometryMath.shortestVectorFromPointToLine(point, line));
+ if (mag < oldMag) {
+ oldMag = mag;
+ bestLine = line;
+ }
+ }
+ return bestLine;
+ }
+
+ /**
+ * Checks if a given point is within a rotated rectangle.
+ *
+ * @param point 2D point to check
+ * @param bound rectangle to rotate
+ * @param rot angle of rotation about rectangle center
+ * @return true if point is within rotated rectangle
+ */
+ public static boolean pointInRotatedRect(float[] point, RectF bound, float rot) {
+ Matrix m = new Matrix();
+ float[] p = Arrays.copyOf(point, 2);
+ m.setRotate(rot, bound.centerX(), bound.centerY());
+ Matrix m0 = new Matrix();
+ if (!m.invert(m0))
+ return false;
+ m0.mapPoints(p);
+ return inclusiveContains(bound, p[0], p[1]);
+ }
+
+ /**
+ * Checks if a given point is within a rotated rectangle.
+ *
+ * @param point 2D point to check
+ * @param rotatedRect corners of a rotated rectangle
+ * @param center center of the rotated rectangle
+ * @return true if point is within rotated rectangle
+ */
+ public static boolean pointInRotatedRect(float[] point, float[] rotatedRect, float[] center) {
+ RectF unrotated = new RectF();
+ float angle = getUnrotated(rotatedRect, center, unrotated);
+ return pointInRotatedRect(point, unrotated, angle);
+ }
+
+ /**
+ * Resizes rectangle to have a certain aspect ratio (center remains
+ * stationary).
+ *
+ * @param r rectangle to resize
+ * @param w new width aspect
+ * @param h new height aspect
+ */
+ public static void fixAspectRatio(RectF r, float w, float h) {
+ float scale = Math.min(r.width() / w, r.height() / h);
+ float centX = r.centerX();
+ float centY = r.centerY();
+ float hw = scale * w / 2;
+ float hh = scale * h / 2;
+ r.set(centX - hw, centY - hh, centX + hw, centY + hh);
+ }
+
+ private static float getUnrotated(float[] rotatedRect, float[] center, RectF unrotated) {
+ float dy = rotatedRect[1] - rotatedRect[3];
+ float dx = rotatedRect[0] - rotatedRect[2];
+ float angle = (float) (Math.atan(dy / dx) * 180 / Math.PI);
+ Matrix m = new Matrix();
+ m.setRotate(-angle, center[0], center[1]);
+ float[] unrotatedRect = new float[rotatedRect.length];
+ m.mapPoints(unrotatedRect, rotatedRect);
+ unrotated.set(trapToRect(unrotatedRect));
+ return angle;
+ }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java
index 33a3f73cb..568dadfc3 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMath.java
@@ -16,6 +16,7 @@
package com.android.gallery3d.filtershow.imageshow;
+import android.graphics.Rect;
import android.graphics.RectF;
public class GeometryMath {
@@ -25,11 +26,37 @@ public class GeometryMath {
return Math.max(Math.min(i, high), low);
}
- protected static float[] shortestVectorFromPointToLine(float[] point, float[] l1, float[] l2) {
- float x1 = l1[0];
- float x2 = l2[0];
- float y1 = l1[1];
- float y2 = l2[1];
+ 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)
@@ -39,64 +66,78 @@ public class GeometryMath {
float[] ret = {
(x1 + u * (x2 - x1)), (y1 + u * (y2 - y1))
};
- float [] vec = {ret[0] - point[0], ret[1] - point[1] };
+ float[] vec = {
+ ret[0] - point[0], ret[1] - point[1]
+ };
return vec;
}
// A . B
- public static float dotProduct(float[] a, float[] b){
+ public static float dotProduct(float[] a, float[] b) {
return a[0] * b[0] + a[1] * b[1];
}
- public static float[] normalize(float[] a){
+ 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 };
+ float[] b = {
+ a[0] / length, a[1] / length
+ };
return b;
}
// A onto B
- public static float scalarProjection(float[] a, float[] 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] };
+ 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] };
+ 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){
+ 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){
+ 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++){
+ 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){
+ 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);
+ 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/GeometryMetadata.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
index cf52b15ca..b53284061 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
@@ -21,12 +21,11 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
+import com.android.gallery3d.filtershow.CropExtras;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.ImageFilterGeometry;
public class GeometryMetadata {
- // Applied in order: rotate, crop, scale.
- // Do not scale saved image (presumably?).
private static final ImageFilterGeometry mImageFilter = new ImageFilterGeometry();
private static final String LOGTAG = "GeometryMetadata";
private float mScaleFactor = 1.0f;
@@ -36,12 +35,29 @@ public class GeometryMetadata {
private final RectF mPhotoBounds = new RectF();
private FLIP mFlip = FLIP.NONE;
- private RectF mBounds = new RectF();
-
public enum FLIP {
NONE, VERTICAL, HORIZONTAL, BOTH
}
+ // Output format data from intent extras
+ private boolean mUseCropExtras = false;
+ private CropExtras mCropExtras = null;
+ public void setUseCropExtrasFlag(boolean f){
+ mUseCropExtras = f;
+ }
+
+ public boolean getUseCropExtrasFlag(){
+ return mUseCropExtras;
+ }
+
+ public void setCropExtras(CropExtras e){
+ mCropExtras = e;
+ }
+
+ public CropExtras getCropExtras(){
+ return mCropExtras;
+ }
+
public GeometryMetadata() {
}
@@ -59,10 +75,8 @@ public class GeometryMetadata {
if (mStraightenRotation != 0) {
return true;
}
- Rect cropBounds = new Rect();
- mCropBounds.roundOut(cropBounds);
- Rect photoBounds = new Rect();
- mPhotoBounds.roundOut(photoBounds);
+ Rect cropBounds = GeometryMath.roundNearest(mCropBounds);
+ Rect photoBounds = GeometryMath.roundNearest(mPhotoBounds);
if (!cropBounds.equals(photoBounds)) {
return true;
}
@@ -88,7 +102,11 @@ public class GeometryMetadata {
mCropBounds.set(g.mCropBounds);
mPhotoBounds.set(g.mPhotoBounds);
mFlip = g.mFlip;
- mBounds = g.mBounds;
+
+ mUseCropExtras = g.mUseCropExtras;
+ if (g.mCropExtras != null){
+ mCropExtras = new CropExtras(g.mCropExtras);
+ }
}
public float getScaleFactor() {
@@ -186,48 +204,16 @@ public class GeometryMetadata {
+ ",photoRect=" + mPhotoBounds.toShortString() + "]";
}
- // TODO: refactor away
- protected static Matrix getHorizontalMatrix(float width) {
- Matrix flipHorizontalMatrix = new Matrix();
- flipHorizontalMatrix.setScale(-1, 1);
- flipHorizontalMatrix.postTranslate(width, 0);
- return flipHorizontalMatrix;
- }
-
protected static void concatHorizontalMatrix(Matrix m, float width) {
m.postScale(-1, 1);
m.postTranslate(width, 0);
}
- // TODO: refactor away
- protected static Matrix getVerticalMatrix(float height) {
- Matrix flipVerticalMatrix = new Matrix();
- flipVerticalMatrix.setScale(1, -1);
- flipVerticalMatrix.postTranslate(0, height);
- return flipVerticalMatrix;
- }
-
protected static void concatVerticalMatrix(Matrix m, float height) {
m.postScale(1, -1);
m.postTranslate(0, height);
}
- // TODO: refactor away
- public static Matrix getFlipMatrix(float width, float height, FLIP type) {
- if (type == FLIP.HORIZONTAL) {
- return getHorizontalMatrix(width);
- } else if (type == FLIP.VERTICAL) {
- return getVerticalMatrix(height);
- } else if (type == FLIP.BOTH) {
- Matrix flipper = getVerticalMatrix(height);
- flipper.postConcat(getHorizontalMatrix(width));
- return flipper;
- } else {
- Matrix m = new Matrix();
- m.reset(); // identity
- return m;
- }
- }
public static void concatMirrorMatrix(Matrix m, float width, float height, FLIP type) {
if (type == FLIP.HORIZONTAL) {
@@ -333,46 +319,10 @@ public class GeometryMetadata {
return m1;
}
- // TODO: refactor away
- public Matrix getFlipMatrix(float width, float height) {
- FLIP type = getFlipType();
- return getFlipMatrix(width, height, type);
- }
-
public boolean hasSwitchedWidthHeight() {
return (((int) (mRotation / 90)) % 2) != 0;
}
- // TODO: refactor away
- public Matrix buildGeometryMatrix(float width, float height, float scaling, float dx, float dy,
- float rotation) {
- float dx0 = width / 2;
- float dy0 = height / 2;
- Matrix m = getFlipMatrix(width, height);
- m.postTranslate(-dx0, -dy0);
- m.postRotate(rotation);
- m.postScale(scaling, scaling);
- m.postTranslate(dx, dy);
- return m;
- }
-
- // TODO: refactor away
- public Matrix buildGeometryMatrix(float width, float height, float scaling, float dx, float dy,
- boolean onlyRotate) {
- float rot = mRotation;
- if (!onlyRotate) {
- rot += mStraightenRotation;
- }
- return buildGeometryMatrix(width, height, scaling, dx, dy, rot);
- }
-
- // TODO: refactor away
- public Matrix buildGeometryUIMatrix(float scaling, float dx, float dy) {
- float w = mPhotoBounds.width();
- float h = mPhotoBounds.height();
- return buildGeometryMatrix(w, h, scaling, dx, dy, false);
- }
-
public static Matrix buildPhotoMatrix(RectF photo, RectF crop, float rotation,
float straighten, FLIP type) {
Matrix m = new Matrix();
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
index 35e8ad4b7..cd1ad5178 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
@@ -29,22 +29,25 @@ import android.util.AttributeSet;
import android.util.Log;
import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.CropExtras;
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
+ // 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 final float MIN_CROP_WIDTH_HEIGHT = 0.1f;
+ private static int mMinSideSize = 100;
private static int mTouchTolerance = 45;
private boolean mFirstDraw = true;
@@ -53,15 +56,33 @@ public class ImageCrop extends ImageGeometry {
private boolean mFixAspectRatio = false;
private float mLastRot = 0;
- private final Paint borderPaint;
+ 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 int mAspectTextSize = 24;
+
+ public void setAspectTextSize(int textSize) {
+ mAspectTextSize = textSize;
+ }
+
+ public void setAspectString(String a) {
+ mAspect = a;
+ }
+
private static final Paint gPaint = new Paint();
public ImageCrop(Context context) {
@@ -69,10 +90,6 @@ public class ImageCrop extends ImageGeometry {
Resources resources = context.getResources();
cropIndicator = resources.getDrawable(R.drawable.camera_crop);
indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
- borderPaint = new Paint();
- borderPaint.setStyle(Paint.Style.STROKE);
- borderPaint.setColor(mBorderColor);
- borderPaint.setStrokeWidth(2f);
}
public ImageCrop(Context context, AttributeSet attrs) {
@@ -80,10 +97,6 @@ public class ImageCrop extends ImageGeometry {
Resources resources = context.getResources();
cropIndicator = resources.getDrawable(R.drawable.camera_crop);
indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
- borderPaint = new Paint();
- borderPaint.setStyle(Paint.Style.STROKE);
- borderPaint.setColor(mBorderColor);
- borderPaint.setStrokeWidth(2f);
}
@Override
@@ -91,84 +104,46 @@ public class ImageCrop extends ImageGeometry {
return getContext().getString(R.string.crop);
}
- private void swapAspect(){
+ private void swapAspect() {
+ if (mDoingCropIntentAction) {
+ return;
+ }
float temp = mAspectWidth;
mAspectWidth = mAspectHeight;
mAspectHeight = temp;
}
- public static void setTouchTolerance(int tolerance){
+ /**
+ * Set tolerance for crop marker selection (in pixels)
+ */
+ public static void setTouchTolerance(int tolerance) {
mTouchTolerance = tolerance;
}
- private boolean switchCropBounds(int moving_corner, RectF dst) {
- RectF crop = getCropBoundsDisplayed();
- float dx1 = 0;
- float dy1 = 0;
- float dx2 = 0;
- float dy2 = 0;
- if ((moving_corner & MOVE_RIGHT) != 0) {
- dx1 = mCurrentX - crop.right;
- } else if ((moving_corner & MOVE_LEFT) != 0) {
- dx1 = mCurrentX - crop.left;
- }
- if ((moving_corner & MOVE_BOTTOM) != 0) {
- dy1 = mCurrentY - crop.bottom;
- } else if ((moving_corner & MOVE_TOP) != 0) {
- dy1 = mCurrentY - crop.top;
- }
- RectF newCrop = null;
- //Fix opposite corner in place and move sides
- if (moving_corner == BOTTOM_RIGHT) {
- newCrop = new RectF(crop.left, crop.top, crop.left + crop.height(), crop.top
- + crop.width());
- } else if (moving_corner == BOTTOM_LEFT) {
- newCrop = new RectF(crop.right - crop.height(), crop.top, crop.right, crop.top
- + crop.width());
- } else if (moving_corner == TOP_LEFT) {
- newCrop = new RectF(crop.right - crop.height(), crop.bottom - crop.width(),
- crop.right, crop.bottom);
- } else if (moving_corner == TOP_RIGHT) {
- newCrop = new RectF(crop.left, crop.bottom - crop.width(), crop.left
- + crop.height(), crop.bottom);
- }
- if ((moving_corner & MOVE_RIGHT) != 0) {
- dx2 = mCurrentX - newCrop.right;
- } else if ((moving_corner & MOVE_LEFT) != 0) {
- dx2 = mCurrentX - newCrop.left;
- }
- if ((moving_corner & MOVE_BOTTOM) != 0) {
- dy2 = mCurrentY - newCrop.bottom;
- } else if ((moving_corner & MOVE_TOP) != 0) {
- dy2 = mCurrentY - newCrop.top;
- }
- if (Math.sqrt(dx1*dx1 + dy1*dy1) > Math.sqrt(dx2*dx2 + dy2*dy2)){
- Matrix m = getCropBoundDisplayMatrix();
- Matrix m0 = new Matrix();
- if (!m.invert(m0)){
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO INVERT CROP MATRIX");
- return false;
- }
- if (!m0.mapRect(newCrop)){
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO MAP RECTANGLE TO RECTANGLE");
- return false;
- }
- swapAspect();
- dst.set(newCrop);
- return true;
- }
- return false;
+ /**
+ * Set minimum side length for crop box (in pixels)
+ */
+ public static void setMinCropSize(int minHeightWidth) {
+ mMinSideSize = minHeightWidth;
+ }
+
+ public void setExtras(CropExtras e) {
+ mCropExtras = e;
+ }
+
+ public void setCropActionFlag(boolean f) {
+ mDoingCropIntentAction = f;
}
- public void apply(float w, float h){
+ public void apply(float w, float h) {
mFixAspectRatio = true;
mAspectWidth = w;
mAspectHeight = h;
setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
getLocalStraighten()));
- cropSetup();
+ if (mVisibilityGained) {
+ cropSetup();
+ }
saveAndSetPreset();
invalidate();
}
@@ -183,202 +158,159 @@ public class ImageCrop extends ImageGeometry {
mAspectHeight = h / scale;
setLocalCropBounds(getUntranslatedStraightenCropBounds(photobounds,
getLocalStraighten()));
- cropSetup();
+ if (mVisibilityGained) {
+ cropSetup();
+ }
saveAndSetPreset();
invalidate();
}
public void applyClear() {
mFixAspectRatio = false;
+ mAspectWidth = 1;
+ mAspectHeight = 1;
setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
getLocalStraighten()));
- cropSetup();
+ if (mVisibilityGained) {
+ cropSetup();
+ }
saveAndSetPreset();
invalidate();
}
- private float getScaledMinWidthHeight() {
- RectF disp = new RectF(0, 0, getWidth(), getHeight());
- float scaled = Math.min(disp.width(), disp.height()) * MIN_CROP_WIDTH_HEIGHT
- / computeScale(getWidth(), getHeight());
- return scaled;
- }
-
- protected Matrix getCropRotationMatrix(float rotation, RectF localImage) {
- Matrix m = getLocalGeoFlipMatrix(localImage.width(), localImage.height());
- m.postRotate(rotation, localImage.centerX(), localImage.centerY());
- if (!m.rectStaysRect()) {
- return null;
- }
- return m;
- }
-
- protected Matrix getCropBoundDisplayMatrix(){
- Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds());
- if (m == null) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO MAP CROP BOUNDS TO RECTANGLE");
- m = new Matrix();
- }
- float zoom = computeScale(getWidth(), getHeight());
- m.postTranslate(mXOffset, mYOffset);
- m.postScale(zoom, zoom, mCenterX, mCenterY);
- return m;
- }
-
- protected RectF getCropBoundsDisplayed() {
- RectF bounds = getLocalCropBounds();
- RectF crop = new RectF(bounds);
- Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds());
-
- if (m == null) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO MAP CROP BOUNDS TO RECTANGLE");
- m = new Matrix();
+ public void clear() {
+ if (mCropExtras != null) {
+ int x = mCropExtras.getAspectX();
+ int y = mCropExtras.getAspectY();
+ if (mDoingCropIntentAction && x > 0 && y > 0) {
+ apply(x, y);
+ }
} else {
- m.mapRect(crop);
+ applyClear();
}
- m = new Matrix();
- float zoom = computeScale(getWidth(), getHeight());
- m.setScale(zoom, zoom, mCenterX, mCenterY);
- m.preTranslate(mXOffset, mYOffset);
- m.mapRect(crop);
- return crop;
}
- private RectF getRotatedCropBounds() {
- RectF bounds = getLocalCropBounds();
- RectF crop = new RectF(bounds);
- Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds());
-
- if (m == null) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO MAP CROP BOUNDS TO RECTANGLE");
- return null;
- } else {
- m.mapRect(crop);
- }
- return crop;
+ 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(), getLocalFlip(), displayCenter);
+ m.preScale(scale, scale);
+ return m;
}
- private RectF getUnrotatedCropBounds(RectF cropBounds) {
- Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds());
-
- if (m == null) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO GET ROTATION MATRIX");
- return null;
- }
- Matrix m0 = new Matrix();
- if (!m.invert(m0)) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO INVERT ROTATION MATRIX");
- return null;
- }
- RectF crop = new RectF(cropBounds);
- if (!m0.mapRect(crop)) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO UNROTATE CROPPING BOUNDS");
- return null;
- }
- return crop;
+ 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(), getLocalFlip(), displayCenter);
+ m1.preScale(scale, scale);
+ return m1;
}
- private RectF getRotatedStraightenBounds() {
- RectF straightenBounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
- getLocalStraighten());
- Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds());
-
- if (m == null) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO MAP STRAIGHTEN BOUNDS TO RECTANGLE");
- return null;
- } else {
- m.mapRect(straightenBounds);
- }
- return straightenBounds;
+ /**
+ * 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 void setCropBounds(RectF bounds) {
- // Avoid cropping smaller than minimum width or height.
+ public boolean setCropBounds(RectF bounds) {
RectF cbounds = new RectF(bounds);
- float minWidthHeight = getScaledMinWidthHeight();
- float aw = mAspectWidth;
- float ah = mAspectHeight;
- if (mFixAspectRatio) {
- minWidthHeight /= aw * ah;
- int r = (int) (getLocalRotation() / 90);
- if (r % 2 != 0) {
- float temp = aw;
- aw = ah;
- ah = temp;
- }
- }
-
+ 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();
- if (mFixAspectRatio) {
- if (newWidth < (minWidthHeight * aw) || newHeight < (minWidthHeight * ah)) {
- newWidth = minWidthHeight * aw;
- newHeight = minWidthHeight * ah;
- }
- } else {
- if (newWidth < minWidthHeight) {
- newWidth = minWidthHeight;
- }
- if (newHeight < minWidthHeight) {
- newHeight = minWidthHeight;
- }
- }
+ float scale = getTransformState(null, null, null);
+ float minWidthHeight = mMinSideSize / scale;
RectF pbounds = getLocalPhotoBounds();
- if (pbounds.width() < minWidthHeight) {
- newWidth = pbounds.width();
+
+ // if photo is smaller than minimum, refuse to set crop bounds
+ if (pbounds.width() < minWidthHeight || pbounds.height() < minWidthHeight) {
+ return false;
}
- if (pbounds.height() < minWidthHeight) {
- newHeight = pbounds.height();
+
+ // if incoming crop is smaller than minimum, refuse to set crop bounds
+ if (newWidth < minWidthHeight || newHeight < minWidthHeight) {
+ return false;
}
- cbounds.set(cbounds.left, cbounds.top, cbounds.left + newWidth, cbounds.top + newHeight);
- RectF straightenBounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
- getLocalStraighten());
- cbounds.intersect(straightenBounds);
+ float newX = bounds.centerX() - (getWidth() / 2f);
+ float newY = bounds.centerY() - (getHeight() / 2f);
+ mOffset[0] = newX;
+ mOffset[1] = newY;
- if (mFixAspectRatio) {
- fixAspectRatio(cbounds, aw, ah);
- }
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) {
- RectF cropped = getCropBoundsDisplayed();
+ Matrix m = getCropBoundDisplayedMatrix();
+ RectF cropped = getLocalCropBounds();
+ m.mapRect(cropped);
+ mBounded = getBoundedCrop(cropped);
movingEdges = 0;
- // Check left or right.
float left = Math.abs(x - cropped.left);
float right = Math.abs(x - cropped.right);
- if ((left <= mTouchTolerance) && (left < 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) {
+ else if ((right <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
+ && ((y - mTouchTolerance) <= cropped.bottom)) {
movingEdges |= MOVE_RIGHT;
}
// Check top or bottom.
- float top = Math.abs(y - cropped.top);
- float bottom = Math.abs(y - cropped.bottom);
- if ((top <= mTouchTolerance) & (top < bottom)) {
+ if ((top <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
+ && ((x - mTouchTolerance) <= cropped.right) && (top < bottom)) {
movingEdges |= MOVE_TOP;
}
- else if (bottom <= mTouchTolerance) {
+ else if ((bottom <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
+ && ((x - mTouchTolerance) <= cropped.right)) {
movingEdges |= MOVE_BOTTOM;
}
- // Check inside block.
- if (cropped.contains(x, y) && (movingEdges == 0)) {
+ if (movingEdges == 0) {
movingEdges = MOVE_BLOCK;
}
if (mFixAspectRatio && (movingEdges != MOVE_BLOCK)) {
@@ -387,7 +319,7 @@ public class ImageCrop extends ImageGeometry {
invalidate();
}
- private int fixEdgeToCorner(int moving_edges){
+ private int fixEdgeToCorner(int moving_edges) {
if (moving_edges == MOVE_LEFT) {
moving_edges |= MOVE_TOP;
}
@@ -403,9 +335,9 @@ public class ImageCrop extends ImageGeometry {
return moving_edges;
}
- private RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy){
+ private RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy) {
RectF newCrop = null;
- //Fix opposite corner in place and move sides
+ // 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);
@@ -423,120 +355,90 @@ public class ImageCrop extends ImageGeometry {
}
private void moveEdges(float dX, float dY) {
- RectF cropped = getRotatedCropBounds();
- float minWidthHeight = getScaledMinWidthHeight();
- float scale = computeScale(getWidth(), getHeight());
- float deltaX = dX / scale;
- float deltaY = dY / scale;
- int select = movingEdges;
- if (mFixAspectRatio && (select != MOVE_BLOCK)) {
-
- // TODO: add in orientation change for fixed aspect
- /*if (select == TOP_LEFT || select == TOP_RIGHT ||
- select == BOTTOM_LEFT || select == BOTTOM_RIGHT){
- RectF blank = new RectF();
- if(switchCropBounds(select, blank)){
- setCropBounds(blank);
- return;
- }
- }*/
- if (select == MOVE_LEFT) {
- select |= MOVE_TOP;
- }
- if (select == MOVE_TOP) {
- select |= MOVE_LEFT;
- }
- if (select == MOVE_RIGHT) {
- select |= MOVE_BOTTOM;
- }
- if (select == MOVE_BOTTOM) {
- select |= MOVE_RIGHT;
- }
- }
-
- if (select == MOVE_BLOCK) {
- RectF straight = getRotatedStraightenBounds();
- // Move the whole cropped bounds within the photo display bounds.
- deltaX = (deltaX > 0) ? Math.min(straight.right - cropped.right, deltaX)
- : Math.max(straight.left - cropped.left, deltaX);
- deltaY = (deltaY > 0) ? Math.min(straight.bottom - cropped.bottom, deltaY)
- : Math.max(straight.top - cropped.top, deltaY);
- cropped.offset(deltaX, deltaY);
+ 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 ((select & MOVE_LEFT) != 0) {
- dx = Math.min(cropped.left + deltaX, cropped.right - minWidthHeight) - cropped.left;
+ if ((movingEdges & MOVE_LEFT) != 0) {
+ dx = Math.min(crop.left + dX, crop.right - minWidthHeight) - crop.left;
}
- if ((select & MOVE_TOP) != 0) {
- dy = Math.min(cropped.top + deltaY, cropped.bottom - minWidthHeight) - cropped.top;
+ if ((movingEdges & MOVE_TOP) != 0) {
+ dy = Math.min(crop.top + dY, crop.bottom - minWidthHeight) - crop.top;
}
- if ((select & MOVE_RIGHT) != 0) {
- dx = Math.max(cropped.right + deltaX, cropped.left + minWidthHeight)
- - cropped.right;
+ if ((movingEdges & MOVE_RIGHT) != 0) {
+ dx = Math.max(crop.right + dX, crop.left + minWidthHeight)
+ - crop.right;
}
- if ((select & MOVE_BOTTOM) != 0) {
- dy = Math.max(cropped.bottom + deltaY, cropped.top + minWidthHeight)
- - cropped.bottom;
+ if ((movingEdges & MOVE_BOTTOM) != 0) {
+ dy = Math.max(crop.bottom + dY, crop.top + minWidthHeight)
+ - crop.bottom;
}
if (mFixAspectRatio) {
- RectF crop = getCropBoundsDisplayed();
- float [] l1 = {crop.left, crop.bottom};
- float [] l2 = {crop.right, crop.top};
- if(movingEdges == TOP_LEFT || movingEdges == BOTTOM_RIGHT){
+ 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[] 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, select, dx * scale, dy * scale);
- Matrix m = getCropBoundDisplayMatrix();
- Matrix m0 = new Matrix();
- if (!m.invert(m0)){
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO INVERT CROP MATRIX");
- return;
- }
- if (!m0.mapRect(newCrop)){
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO MAP RECTANGLE TO RECTANGLE");
- return;
- }
+ RectF newCrop = fixedCornerResize(crop, movingEdges, dx, dy);
+
+ mBounded.fixedAspectResizeInner(newCrop);
+ newCrop = mBounded.getInner();
setCropBounds(newCrop);
return;
} else {
- if ((select & MOVE_LEFT) != 0) {
- cropped.left += dx;
+ if ((movingEdges & MOVE_LEFT) != 0) {
+ crop.left += dx;
}
- if ((select & MOVE_TOP) != 0) {
- cropped.top += dy;
+ if ((movingEdges & MOVE_TOP) != 0) {
+ crop.top += dy;
}
- if ((select & MOVE_RIGHT) != 0) {
- cropped.right += dx;
+ if ((movingEdges & MOVE_RIGHT) != 0) {
+ crop.right += dx;
}
- if ((select & MOVE_BOTTOM) != 0) {
- cropped.bottom += dy;
+ if ((movingEdges & MOVE_BOTTOM) != 0) {
+ crop.bottom += dy;
}
}
}
- movingEdges = select;
- Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds());
- Matrix m0 = new Matrix();
- if (!m.invert(m0)) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO INVERT ROTATION MATRIX");
- }
- if (!m0.mapRect(cropped)) {
- if (LOGV)
- Log.v(LOGTAG, "FAILED TO UNROTATE CROPPING BOUNDS");
- }
- setCropBounds(cropped);
+ mBounded.resizeInner(crop);
+ crop = mBounded.getInner();
+ setCropBounds(crop);
}
private void drawIndicator(Canvas canvas, Drawable indicator, float centerX, float centerY) {
@@ -549,7 +451,8 @@ public class ImageCrop extends ImageGeometry {
@Override
protected void setActionDown(float x, float y) {
super.setActionDown(x, y);
- detectMovingEdges(x, y);
+ detectMovingEdges(x + mOffset[0], y + mOffset[1]);
+
}
@Override
@@ -560,20 +463,54 @@ public class ImageCrop extends ImageGeometry {
@Override
protected void setActionMove(float x, float y) {
- if (movingEdges != 0){
+
+ if (movingEdges != 0) {
moveEdges(x - mCurrentX, y - mCurrentY);
}
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) {
- RectF cb = getRotatedCropBounds();
- fixAspectRatio(cb, mAspectWidth, mAspectHeight);
- RectF cb0 = getUnrotatedCropBounds(cb);
- setCropBounds(cb0);
- } else {
- setCropBounds(getLocalCropBounds());
+ 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);
+ }
}
}
@@ -581,7 +518,7 @@ public class ImageCrop extends ImageGeometry {
public void imageLoaded() {
super.imageLoaded();
syncLocalToMasterGeometry();
- applyOriginal();
+ clear();
invalidate();
}
@@ -589,7 +526,7 @@ public class ImageCrop extends ImageGeometry {
protected void gainedVisibility() {
float rot = getLocalRotation();
// if has changed orientation via rotate
- if( ((int) ((rot - mLastRot) / 90)) % 2 != 0 ){
+ if (((int) ((rot - mLastRot) / 90)) % 2 != 0) {
swapAspect();
}
cropSetup();
@@ -599,7 +536,6 @@ public class ImageCrop extends ImageGeometry {
@Override
public void resetParameter() {
super.resetParameter();
- cropSetup();
}
@Override
@@ -624,72 +560,109 @@ public class ImageCrop extends ImageGeometry {
@Override
protected void drawShape(Canvas canvas, Bitmap image) {
- // TODO: move style to xml
gPaint.setAntiAlias(true);
- gPaint.setFilterBitmap(true);
- gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
if (mFirstDraw) {
cropSetup();
mFirstDraw = false;
}
- float rotation = getLocalRotation();
- RectF crop = drawTransformed(canvas, image, gPaint);
+ RectF crop = drawTransformed(canvas, image, gPaint, mOffset);
gPaint.setColor(mBorderColor);
gPaint.setStrokeWidth(3);
gPaint.setStyle(Paint.Style.STROKE);
- drawRuleOfThird(canvas, crop, gPaint);
- gPaint.setColor(mBorderColor);
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
- drawStraighten(canvas, gPaint);
-
- int decoded_moving = decoder(movingEdges, rotation);
- canvas.save();
- canvas.rotate(rotation, mCenterX, mCenterY);
- RectF scaledCrop = unrotatedCropBounds();
- boolean notMoving = decoded_moving == 0;
- if (((decoded_moving & MOVE_TOP) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top);
- }
- if (((decoded_moving & MOVE_BOTTOM) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.bottom);
- }
- if (((decoded_moving & MOVE_LEFT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.centerY());
+ 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 (((decoded_moving & MOVE_RIGHT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.centerY());
+
+ if (doThirds) {
+ drawRuleOfThird(canvas, crop, gPaint);
+
}
- canvas.restore();
- }
-
- 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;
- }
-
- protected int decoder(int movingEdges, float rotation) {
- int rot = constrainedRotation(rotation);
- switch (rot) {
- case 90:
- return bitCycleLeft(movingEdges, 3, 4);
- case 180:
- return bitCycleLeft(movingEdges, 2, 4);
- case 270:
- return bitCycleLeft(movingEdges, 1, 4);
- default:
- return movingEdges;
+
+ 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());
+ }
}
}
+
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java b/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
index 5d6fe502f..6bfba1b2c 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
@@ -136,8 +136,6 @@ public class ImageFlip extends ImageGeometry {
@Override
protected void drawShape(Canvas canvas, Bitmap image) {
gPaint.setAntiAlias(true);
- gPaint.setFilterBitmap(true);
- gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
drawTransformedCropped(canvas, image, gPaint);
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java b/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
index 42dd139bc..c8ae444da 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
@@ -33,7 +33,7 @@ import com.android.gallery3d.filtershow.imageshow.GeometryMetadata.FLIP;
import com.android.gallery3d.filtershow.presets.ImagePreset;
public abstract class ImageGeometry extends ImageSlave {
- private boolean mVisibilityGained = false;
+ protected boolean mVisibilityGained = false;
private boolean mHasDrawn = false;
protected static final float MAX_STRAIGHTEN_ANGLE = 45;
@@ -191,8 +191,8 @@ public abstract class ImageGeometry extends ImageSlave {
return r * 90;
}
- protected Matrix getLocalGeoFlipMatrix(float width, float height) {
- return mLocalGeometry.getFlipMatrix(width, height);
+ protected boolean isHeightWidthSwapped() {
+ return ((int) (getLocalRotation() / 90)) % 2 != 0;
}
protected void setLocalStraighten(float r) {
@@ -217,32 +217,6 @@ public abstract class ImageGeometry extends ImageSlave {
return getLocalRotation() + getLocalStraighten();
}
- protected static float[] getCornersFromRect(RectF r) {
- // Order is:
- // 0------->1
- // ^ |
- // | v
- // 3<-------2
- float[] corners = {
- r.left, r.top, // 0
- r.right, r.top, // 1
- r.right, r.bottom,// 2
- r.left, r.bottom // 3
- };
- return corners;
- }
-
- // If edge point [x, y] in array [x0, y0, x1, y1, ...] is outside of the
- // image bound rectangle, clamps it to the edge of the rectangle.
- protected static void getEdgePoints(RectF imageBound, float[] array) {
- if (array.length < 2)
- return;
- for (int x = 0; x < array.length; x += 2) {
- array[x] = GeometryMath.clamp(array[x], imageBound.left, imageBound.right);
- array[x + 1] = GeometryMath.clamp(array[x + 1], imageBound.top, imageBound.bottom);
- }
- }
-
protected static Path drawClosedPath(Canvas canvas, Paint paint, float[] points) {
Path crop = new Path();
crop.moveTo(points[0], points[1]);
@@ -254,16 +228,6 @@ public abstract class ImageGeometry extends ImageSlave {
return crop;
}
- protected static void fixAspectRatio(RectF r, float w, float h) {
- float scale = Math.min(r.width() / w, r.height() / h);
- float centX = r.centerX();
- float centY = r.centerY();
- float hw = scale * w / 2;
- float hh = scale * h / 2;
- r.set(centX - hw, centY - hh, centX + hw, centY + hh);
-
- }
-
protected static float getNewHeightForWidthAspect(float width, float w, float h) {
return width * h / w;
}
@@ -290,11 +254,11 @@ public abstract class ImageGeometry extends ImageSlave {
}
protected void gainedVisibility() {
- // TODO: Override this stub.
+ // Override this stub.
}
protected void lostVisibility() {
- // TODO: Override this stub.
+ // Override this stub.
}
@Override
@@ -327,7 +291,7 @@ public abstract class ImageGeometry extends ImageSlave {
}
protected int getLocalValue() {
- return 0; // TODO: Override this
+ return 0; // Override this
}
protected void setActionDown(float x, float y) {
@@ -402,110 +366,19 @@ public abstract class ImageGeometry extends ImageSlave {
return new RectF(left, top, right, bottom);
}
- protected Matrix getGeoMatrix(RectF r, boolean onlyRotate) {
- RectF pbounds = getLocalPhotoBounds();
- float scale = GeometryMath
- .scale(pbounds.width(), pbounds.height(), getWidth(), getHeight());
- if (((int) (getLocalRotation() / 90)) % 2 != 0) {
- scale = GeometryMath.scale(pbounds.width(), pbounds.height(), getHeight(), getWidth());
- }
- float yoff = getHeight() / 2;
- float xoff = getWidth() / 2;
- float w = r.left * 2 + r.width();
- float h = r.top * 2 + r.height();
- return mLocalGeometry.buildGeometryMatrix(w, h, scale, xoff, yoff, onlyRotate);
- }
-
- protected void drawImageBitmap(Canvas canvas, Bitmap bitmap, Paint paint, Matrix m) {
- canvas.save();
- canvas.drawBitmap(bitmap, m, paint);
- canvas.restore();
- }
-
- protected void drawImageBitmap(Canvas canvas, Bitmap bitmap, Paint paint) {
- float scale = computeScale(getWidth(), getHeight());
- float yoff = getHeight() / 2;
- float xoff = getWidth() / 2;
- Matrix m = mLocalGeometry.buildGeometryUIMatrix(scale, xoff, yoff);
- drawImageBitmap(canvas, bitmap, paint, m);
- }
-
protected RectF straightenBounds() {
RectF bounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
getLocalStraighten());
- Matrix m = getGeoMatrix(bounds, true);
- m.mapRect(bounds);
- return bounds;
- }
-
- protected void drawStraighten(Canvas canvas, Paint paint) {
- RectF bounds = straightenBounds();
- canvas.save();
- canvas.drawRect(bounds, paint);
- canvas.restore();
- }
-
- protected RectF unrotatedCropBounds() {
- RectF bounds = getLocalCropBounds();
- RectF pbounds = getLocalPhotoBounds();
float scale = computeScale(getWidth(), getHeight());
- float yoff = getHeight() / 2;
- float xoff = getWidth() / 2;
- Matrix m = mLocalGeometry.buildGeometryMatrix(pbounds.width(), pbounds.height(), scale,
- xoff, yoff, 0);
- m.mapRect(bounds);
- return bounds;
- }
-
- protected RectF cropBounds() {
- RectF bounds = getLocalCropBounds();
- Matrix m = getGeoMatrix(getLocalPhotoBounds(), true);
- m.mapRect(bounds);
+ bounds = GeometryMath.scaleRect(bounds, scale);
+ float dx = (getWidth() / 2) - bounds.centerX();
+ float dy = (getHeight() / 2) - bounds.centerY();
+ bounds.offset(dx, dy);
return bounds;
}
- // Fails for non-90 degree
- protected void drawCrop(Canvas canvas, Paint paint) {
- RectF bounds = cropBounds();
- canvas.save();
- canvas.drawRect(bounds, paint);
- canvas.restore();
- }
-
- protected void drawCropSafe(Canvas canvas, Paint paint) {
- Matrix m = getGeoMatrix(getLocalPhotoBounds(), true);
- RectF crop = getLocalCropBounds();
- if (!m.rectStaysRect()) {
- float[] corners = getCornersFromRect(crop);
- m.mapPoints(corners);
- drawClosedPath(canvas, paint, corners);
- } else {
- m.mapRect(crop);
- Path path = new Path();
- path.addRect(crop, Path.Direction.CCW);
- canvas.drawPath(path, paint);
- }
- }
-
- protected void drawTransformedBitmap(Canvas canvas, Bitmap bitmap, Paint paint, boolean clip) {
- paint.setARGB(255, 0, 0, 0);
- drawImageBitmap(canvas, bitmap, paint);
- paint.setColor(Color.WHITE);
- paint.setStyle(Style.STROKE);
- paint.setStrokeWidth(2);
- drawCropSafe(canvas, paint);
- paint.setColor(getDefaultBackgroundColor());
- paint.setStyle(Paint.Style.FILL);
- drawShadows(canvas, paint, unrotatedCropBounds());
- }
-
- protected void drawShadows(Canvas canvas, Paint p, RectF innerBounds) {
- RectF display = new RectF(0, 0, getWidth(), getHeight());
- drawShadows(canvas, p, innerBounds, display, getLocalRotation(), getWidth() / 2,
- getHeight() / 2);
- }
-
- protected static void drawShadows(Canvas canvas, Paint p, RectF innerBounds, RectF outerBounds,
+ 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);
@@ -527,6 +400,15 @@ public abstract class ImageGeometry extends ImageSlave {
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) {
if (getDirtyGeometryFlag()) {
@@ -547,21 +429,38 @@ public abstract class ImageGeometry extends ImageSlave {
// TODO: Override this stub.
}
- protected RectF drawTransformed(Canvas canvas, Bitmap photo, Paint p) {
- p.setARGB(255, 0, 0, 0);
+ /**
+ * 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 (((int) (getLocalRotation() / 90)) % 2 != 0) {
+ if (isHeightWidthSwapped()) {
scale = computeScale(getHeight(), getWidth());
}
// put in screen coordinates
- RectF scaledCrop = GeometryMath.scaleRect(cropBounds, scale);
- RectF scaledPhoto = GeometryMath.scaleRect(photoBounds, scale);
- float[] displayCenter = {
- getWidth() / 2f, getHeight() / 2f
- };
+ 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(), getLocalFlip(), displayCenter);
@@ -569,9 +468,11 @@ public abstract class ImageGeometry extends ImageSlave {
getLocalRotation(), getLocalStraighten(), getLocalFlip(), 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();
@@ -580,6 +481,11 @@ public abstract class ImageGeometry extends ImageSlave {
p.setStyle(Style.STROKE);
p.setStrokeWidth(2);
canvas.drawPath(path, p);
+
+ p.setColor(getDefaultBackgroundColor());
+ p.setAlpha(128);
+ p.setStyle(Paint.Style.FILL);
+ drawShadows(canvas, p, scaledCrop);
return scaledCrop;
}
@@ -590,7 +496,7 @@ public abstract class ImageGeometry extends ImageSlave {
float imageHeight = cropBounds.height();
float scale = GeometryMath.scale(imageWidth, imageHeight, getWidth(), getHeight());
// checks if local rotation is an odd multiple of 90.
- if (((int) (getLocalRotation() / 90)) % 2 != 0) {
+ if (isHeightWidthSwapped()) {
scale = GeometryMath.scale(imageWidth, imageHeight, getHeight(), getWidth());
}
// put in screen coordinates
@@ -618,6 +524,8 @@ public abstract class ImageGeometry extends ImageSlave {
p.setStyle(Paint.Style.FILL);
scaledCrop.offset(displayCenter[0] - scaledCrop.centerX(), displayCenter[1]
- scaledCrop.centerY());
- drawShadows(canvas, p, scaledCrop);
+ 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/ImageRedEyes.java b/src/com/android/gallery3d/filtershow/imageshow/ImageRedEyes.java
new file mode 100644
index 000000000..5119dff3c
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageRedEyes.java
@@ -0,0 +1,148 @@
+
+package com.android.gallery3d.filtershow.imageshow;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.gallery3d.filtershow.filters.ImageFilterRedEye;
+import com.android.gallery3d.filtershow.filters.RedEyeCandidate;
+
+public class ImageRedEyes extends ImageSlave {
+
+ private static final String LOGTAG = "ImageRedEyes";
+ private RectF mCurrentRect = null;
+ private static float mTouchPadding = 80;
+
+ public static void setTouchPadding(float padding) {
+ mTouchPadding = padding;
+ }
+
+ public ImageRedEyes(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ImageRedEyes(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void resetParameter() {
+ ImageFilterRedEye filter = (ImageFilterRedEye) getCurrentFilter();
+ if (filter != null) {
+ filter.clear();
+ }
+ mCurrentRect = null;
+ invalidate();
+ }
+
+ @Override
+ public void updateImage() {
+ super.updateImage();
+ invalidate();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+ float ex = event.getX();
+ float ey = event.getY();
+
+ ImageFilterRedEye filter = (ImageFilterRedEye) getCurrentFilter();
+
+ // let's transform (ex, ey) to displayed image coordinates
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ mCurrentRect = new RectF();
+ mCurrentRect.left = ex - mTouchPadding;
+ mCurrentRect.top = ey - mTouchPadding;
+ }
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ mCurrentRect.right = ex + mTouchPadding;
+ mCurrentRect.bottom = ey + mTouchPadding;
+ }
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ if (mCurrentRect != null) {
+ // transform to original coordinates
+ GeometryMetadata geo = getImagePreset().mGeoData;
+ Matrix originalToScreen = geo.getOriginalToScreen(true,
+ mImageLoader.getOriginalBounds().width(),
+ mImageLoader.getOriginalBounds().height(),
+ getWidth(), getHeight());
+ Matrix originalNoRotateToScreen = geo.getOriginalToScreen(false,
+ mImageLoader.getOriginalBounds().width(),
+ mImageLoader.getOriginalBounds().height(),
+ getWidth(), getHeight());
+
+ Matrix invert = new Matrix();
+ originalToScreen.invert(invert);
+ RectF r = new RectF(mCurrentRect);
+ invert.mapRect(r);
+ RectF r2 = new RectF(mCurrentRect);
+ invert.reset();
+ originalNoRotateToScreen.invert(invert);
+ invert.mapRect(r2);
+ filter.addRect(r, r2);
+ this.resetImageCaches(this);
+ }
+ mCurrentRect = null;
+ }
+ invalidate();
+ return true;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ Paint paint = new Paint();
+ paint.setStyle(Style.STROKE);
+ paint.setColor(Color.RED);
+ paint.setStrokeWidth(2);
+ if (mCurrentRect != null) {
+ paint.setColor(Color.RED);
+ RectF drawRect = new RectF(mCurrentRect);
+ canvas.drawRect(drawRect, paint);
+ }
+
+ GeometryMetadata geo = getImagePreset().mGeoData;
+ Matrix originalToScreen = geo.getOriginalToScreen(false,
+ mImageLoader.getOriginalBounds().width(),
+ mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
+ Matrix originalRotateToScreen = geo.getOriginalToScreen(true,
+ mImageLoader.getOriginalBounds().width(),
+ mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
+
+ ImageFilterRedEye filter = (ImageFilterRedEye) getCurrentFilter();
+ for (RedEyeCandidate candidate : filter.getCandidates()) {
+ RectF rect = candidate.getRect();
+ RectF drawRect = new RectF();
+ originalToScreen.mapRect(drawRect, rect);
+ RectF fullRect = new RectF();
+ originalRotateToScreen.mapRect(fullRect, rect);
+ paint.setColor(Color.BLUE);
+ canvas.drawRect(fullRect, paint);
+ canvas.drawLine(fullRect.centerX(), fullRect.top,
+ fullRect.centerX(), fullRect.bottom, paint);
+ canvas.drawLine(fullRect.left, fullRect.centerY(),
+ fullRect.right, fullRect.centerY(), paint);
+ paint.setColor(Color.GREEN);
+ float dw = drawRect.width();
+ float dh = drawRect.height();
+ float dx = fullRect.centerX() - dw/2;
+ float dy = fullRect.centerY() - dh/2;
+ drawRect.set(dx, dy, dx + dw, dy + dh);
+ canvas.drawRect(drawRect, paint);
+ canvas.drawLine(drawRect.centerX(), drawRect.top,
+ drawRect.centerX(), drawRect.bottom, paint);
+ canvas.drawLine(drawRect.left, drawRect.centerY(),
+ drawRect.right, drawRect.centerY(), paint);
+ canvas.drawCircle(drawRect.centerX(), drawRect.centerY(),
+ mTouchPadding, paint);
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java b/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
index a4131ff80..30cc9e2f3 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
@@ -81,8 +81,6 @@ public class ImageRotate extends ImageGeometry {
@Override
protected void drawShape(Canvas canvas, Bitmap image) {
gPaint.setAntiAlias(true);
- gPaint.setFilterBitmap(true);
- gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
drawTransformedCropped(canvas, image, gPaint);
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 358d5b795..4c74b16ca 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -23,6 +23,7 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.net.Uri;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
@@ -74,16 +75,12 @@ public class ImageShow extends View implements OnGestureListener,
private Bitmap mFiltersOnlyImage = null;
private Bitmap mFilteredImage = null;
- private final boolean USE_SLIDER_GESTURE = false; // set to true to have
- // slider gesture
- protected SliderController mSliderController = new SliderController();
-
private GestureDetector mGestureDetector = null;
private HistoryAdapter mHistoryAdapter = null;
private ImageStateAdapter mImageStateAdapter = null;
- private Rect mImageBounds = new Rect();
+ protected Rect mImageBounds = new Rect();
private boolean mTouchShowOriginal = false;
private long mTouchShowOriginalDate = 0;
@@ -152,15 +149,15 @@ public class ImageShow extends View implements OnGestureListener,
private final Handler mHandler = new Handler();
public void select() {
+ if (mSeekBar != null) {
+ mSeekBar.setOnSeekBarChangeListener(this);
+ }
if (getCurrentFilter() != null) {
int parameter = getCurrentFilter().getParameter();
int maxp = getCurrentFilter().getMaxParameter();
int minp = getCurrentFilter().getMinParameter();
updateSeekBar(parameter, minp, maxp);
}
- if (mSeekBar != null) {
- mSeekBar.setOnSeekBarChangeListener(this);
- }
}
private int parameterToUI(int parameter, int minp, int maxp, int uimax) {
@@ -178,9 +175,6 @@ public class ImageShow extends View implements OnGestureListener,
int seekMax = mSeekBar.getMax();
int progress = parameterToUI(parameter, minp, maxp, seekMax);
mSeekBar.setProgress(progress);
- if (getPanelController() != null) {
- getPanelController().onNewValue(parameter);
- }
}
public void unselect() {
@@ -197,10 +191,8 @@ public class ImageShow extends View implements OnGestureListener,
public void resetParameter() {
ImageFilter currentFilter = getCurrentFilter();
if (currentFilter != null) {
- onNewValue(currentFilter.getDefaultParameter());
- }
- if (USE_SLIDER_GESTURE) {
- mSliderController.reset();
+ updateSeekBar(currentFilter.getDefaultParameter(),
+ getCurrentFilter().getMinParameter(), getCurrentFilter().getMaxParameter());
}
}
@@ -214,8 +206,8 @@ public class ImageShow extends View implements OnGestureListener,
@Override
public void onNewValue(int parameter) {
- int maxp = 100;
- int minp = -100;
+ int maxp = ImageFilter.DEFAULT_MAX_PARAMETER;
+ int minp = ImageFilter.DEFAULT_MIN_PARAMETER;
if (getCurrentFilter() != null) {
getCurrentFilter().setParameter(parameter);
maxp = getCurrentFilter().getMaxParameter();
@@ -228,7 +220,6 @@ public class ImageShow extends View implements OnGestureListener,
if (getPanelController() != null) {
getPanelController().onNewValue(parameter);
}
- updateSeekBar(parameter, minp, maxp);
invalidate();
mActivity.enableSave(hasModifications());
}
@@ -246,9 +237,6 @@ public class ImageShow extends View implements OnGestureListener,
public ImageShow(Context context, AttributeSet attrs) {
super(context, attrs);
- if (USE_SLIDER_GESTURE) {
- mSliderController.setListener(this);
- }
mHistoryAdapter = new HistoryAdapter(context, R.layout.filtershow_history_operation_row,
R.id.rowTextView);
mImageStateAdapter = new ImageStateAdapter(context,
@@ -259,9 +247,6 @@ public class ImageShow extends View implements OnGestureListener,
public ImageShow(Context context) {
super(context);
- if (USE_SLIDER_GESTURE) {
- mSliderController.setListener(this);
- }
mHistoryAdapter = new HistoryAdapter(context, R.layout.filtershow_history_operation_row,
R.id.rowTextView);
setupGestureDetector(context);
@@ -277,10 +262,6 @@ public class ImageShow extends View implements OnGestureListener,
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(parentWidth, parentHeight);
- if (USE_SLIDER_GESTURE) {
- mSliderController.setWidth(parentWidth);
- mSliderController.setHeight(parentHeight);
- }
}
public void setSeekBar(SeekBar seekBar) {
@@ -324,6 +305,10 @@ public class ImageShow extends View implements OnGestureListener,
return dst;
}
+ public Rect getImageCropBounds() {
+ return GeometryMath.roundNearest(getImagePreset().mGeoData.getPreviewCropBounds());
+ }
+
public Rect getDisplayedImageBounds() {
return mImageBounds;
}
@@ -378,12 +363,6 @@ public class ImageShow extends View implements OnGestureListener,
1.5f * mTextPadding, mPaint);
}
- if (showControls()) {
- if (USE_SLIDER_GESTURE) {
- mSliderController.onDraw(canvas);
- }
- }
-
drawToast(canvas);
}
@@ -646,13 +625,13 @@ public class ImageShow extends View implements OnGestureListener,
}
public void updateImage() {
+ invalidate();
if (!updateGeometryFlags()) {
return;
}
Bitmap bitmap = mImageLoader.getOriginalBitmapLarge();
if (bitmap != null) {
imageSizeChanged(bitmap);
- invalidate();
}
}
@@ -669,12 +648,17 @@ public class ImageShow extends View implements OnGestureListener,
mImageLoader.saveImage(getImagePreset(), filterShowActivity, file);
}
+ public void saveToUri(Bitmap f, Uri u, String m, FilterShowActivity filterShowActivity) {
+ mImageLoader.saveToUri(f, u, m, filterShowActivity);
+ }
+
+ public void returnFilteredResult(FilterShowActivity filterShowActivity) {
+ mImageLoader.returnFilteredResult(getImagePreset(), filterShowActivity);
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
- if (USE_SLIDER_GESTURE) {
- mSliderController.onTouchEvent(event);
- }
if (mGestureDetector != null) {
mGestureDetector.onTouchEvent(event);
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java b/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java
index 6a79e18a1..2a3ee2856 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java
@@ -47,6 +47,13 @@ public class ImageSmallFilter extends ImageShow implements View.OnClickListener
protected final int mTextColor = Color.WHITE;
private ImageSmallFilter mNullFilter;
+ private Bitmap mOverlayBitmap = null;
+ private final int mOverlayTint = Color.argb(100, 0, 0, 0);
+
+ public void setOverlayBitmap(Bitmap bitmap){
+ mOverlayBitmap = bitmap;
+ }
+
public static void setMargin(int value) {
mMargin = value;
}
@@ -77,6 +84,10 @@ public class ImageSmallFilter extends ImageShow implements View.OnClickListener
mImagePreset.add(mImageFilter);
}
+ public ImageFilter getImageFilter() {
+ return mImageFilter;
+ }
+
@Override
public void setSelected(boolean value) {
if (mIsSelected != value) {
@@ -188,6 +199,13 @@ public class ImageSmallFilter extends ImageShow implements View.OnClickListener
mPaint.setTextSize(mTextSize);
mPaint.setColor(mTextColor);
canvas.drawText(mImageFilter.getName(), x, y - mTextMargin, mPaint);
+ if (mOverlayBitmap != null) {
+ mPaint.setColor(mOverlayTint);
+ canvas.drawRect(0, mMargin, getWidth(), getWidth() + mMargin, mPaint);
+ Rect d = new Rect(0, mMargin, getWidth() - mMargin, getWidth());
+ mPaint.setColor(Color.BLACK);
+ drawImage(canvas, mOverlayBitmap, d);
+ }
}
public void drawImage(Canvas canvas, Bitmap image, Rect destination) {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
index 57a22aab3..7a539da8f 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
@@ -20,6 +20,7 @@ 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.Path;
import android.graphics.RectF;
@@ -105,10 +106,10 @@ public class ImageStraighten extends ImageGeometry {
@Override
protected void drawShape(Canvas canvas, Bitmap image) {
- drawTransformed(canvas, image, gPaint);
+ float [] o = {0, 0};
+ RectF bounds = drawTransformed(canvas, image, gPaint, o);
// Draw the grid
- RectF bounds = straightenBounds();
Path path = new Path();
path.addRect(bounds, Path.Direction.CCW);
gPaint.setARGB(255, 255, 255, 255);
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java b/src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java
deleted file mode 100644
index a332fa72a..000000000
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java
+++ /dev/null
@@ -1,50 +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.Rect;
-
-/**
- * TODO: Insert description here. (generated by hoford)
- */
-public class ImageWithIcon extends ImageSmallFilter {
- /**
- * @param context
- */
- public ImageWithIcon(Context context) {
- super(context);
- // TODO(hoford): Auto-generated constructor stub
- }
-
- private Bitmap bitmap;
-
- public void setIcon(Bitmap bitmap){
- this.bitmap = bitmap;
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (bitmap != null) {
- Rect d = new Rect(0, mMargin, getWidth() - mMargin, getWidth());
- drawImage(canvas, bitmap, d);
- }
- }
-}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
index c7586fe9b..b66da0128 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
@@ -128,10 +128,6 @@ public class ImageZoom extends ImageSlave {
drawImage(canvas, filteredImage);
canvas.restore();
- if (showControls()) {
- mSliderController.onDraw(canvas);
- }
-
drawToast(canvas);
}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
index 8943f30de..2522c8966 100644
--- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
@@ -181,7 +181,7 @@ public class ImagePreset {
return false;
}
- if (mImageBorder != preset.mImageBorder) {
+ if (mDoApplyGeometry && mImageBorder != preset.mImageBorder) {
return false;
}
@@ -292,7 +292,7 @@ public class ImagePreset {
}
}
- if (mImageBorder != null) {
+ if (mImageBorder != null && mDoApplyGeometry) {
bitmap = mImageBorder.apply(bitmap, mScaleFactor, mIsHighQuality);
}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetBW.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetBW.java
deleted file mode 100644
index bfa6dacc7..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetBW.java
+++ /dev/null
@@ -1,33 +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.presets;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterBW;
-
-public class ImagePresetBW extends ImagePreset {
-
- @Override
- public String name() {
- return "B&W";
- }
-
- @Override
- public void setup() {
- mFilters.add(new ImageFilterBW());
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetBWBlue.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetBWBlue.java
deleted file mode 100644
index 5d56aa1cd..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetBWBlue.java
+++ /dev/null
@@ -1,33 +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.presets;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterBWBlue;
-
-public class ImagePresetBWBlue extends ImagePreset {
-
- @Override
- public String name() {
- return "B&W - Blue";
- }
-
- @Override
- public void setup() {
- mFilters.add(new ImageFilterBWBlue());
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetBWGreen.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetBWGreen.java
deleted file mode 100644
index d1b4e5d78..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetBWGreen.java
+++ /dev/null
@@ -1,33 +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.presets;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterBWGreen;
-
-public class ImagePresetBWGreen extends ImagePreset {
-
- @Override
- public String name() {
- return "B&W - Green";
- }
-
- @Override
- public void setup() {
- mFilters.add(new ImageFilterBWGreen());
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetBWRed.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetBWRed.java
deleted file mode 100644
index 9653bed57..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetBWRed.java
+++ /dev/null
@@ -1,33 +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.presets;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterBWRed;
-
-public class ImagePresetBWRed extends ImagePreset {
-
- @Override
- public String name() {
- return "B&W - Red";
- }
-
- @Override
- public void setup() {
- mFilters.add(new ImageFilterBWRed());
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java
deleted file mode 100644
index 95edc5d15..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java
+++ /dev/null
@@ -1,45 +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.presets;
-
-import android.graphics.Bitmap;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterFx;
-
-public class ImagePresetFX extends ImagePreset {
- String name;
- Bitmap fxBitmap;
-
- @Override
- public String name() {
- return name;
- }
-
- public ImagePresetFX(Bitmap bitmap, String name) {
- fxBitmap = bitmap;
- this.name = name;
- setup();
- }
-
- @Override
- public void setup() {
- if (fxBitmap != null) {
- mFilters.add(new ImageFilterFx(fxBitmap,name));
- }
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetOld.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetOld.java
deleted file mode 100644
index 5e1db8336..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetOld.java
+++ /dev/null
@@ -1,38 +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.presets;
-
-import android.graphics.Color;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterGradient;
-
-public class ImagePresetOld extends ImagePreset {
-
- @Override
- public String name() {
- return "Old";
- }
-
- @Override
- public void setup() {
- ImageFilterGradient filter = new ImageFilterGradient();
- filter.addColor(Color.BLACK, 0.0f);
- filter.addColor(Color.argb(255, 228, 231, 193), 1.0f);
- mFilters.add(filter);
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetSaturated.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetSaturated.java
deleted file mode 100644
index ddfca7508..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetSaturated.java
+++ /dev/null
@@ -1,35 +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.presets;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterSaturated;
-
-public class ImagePresetSaturated extends ImagePreset {
-
- @Override
- public String name() {
- return "Saturated";
- }
-
- @Override
- public void setup() {
- ImageFilterSaturated filter = new ImageFilterSaturated();
- filter.setParameter(50);
- mFilters.add(filter);
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetXProcessing.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetXProcessing.java
deleted file mode 100644
index 7957b5e7c..000000000
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetXProcessing.java
+++ /dev/null
@@ -1,39 +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.presets;
-
-import android.graphics.Color;
-
-import com.android.gallery3d.filtershow.filters.ImageFilterGradient;
-
-public class ImagePresetXProcessing extends ImagePreset {
-
- @Override
- public String name() {
- return "X-Process";
- }
-
- @Override
- public void setup() {
- ImageFilterGradient filter = new ImageFilterGradient();
- filter.addColor(Color.BLACK, 0.0f);
- filter.addColor(Color.argb(255, 29, 82, 83), 0.4f);
- filter.addColor(Color.argb(255, 211, 217, 186), 1.0f);
- mFilters.add(filter);
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/tools/BitmapTask.java b/src/com/android/gallery3d/filtershow/tools/BitmapTask.java
new file mode 100644
index 000000000..62801c1f2
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/tools/BitmapTask.java
@@ -0,0 +1,68 @@
+/*
+ * 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.tools;
+
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+
+/**
+ * Asynchronous task filtering or doign I/O with bitmaps.
+ */
+public class BitmapTask <T> extends AsyncTask<T, Void, Bitmap> {
+
+ private Callbacks<T> mCallbacks;
+ private static final String LOGTAG = "BitmapTask";
+
+ public BitmapTask(Callbacks<T> callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ protected Bitmap doInBackground(T... params) {
+ if (params == null || mCallbacks == null) {
+ return null;
+ }
+ return mCallbacks.onExecute(params[0]);
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap result) {
+ if (mCallbacks == null) {
+ return;
+ }
+ mCallbacks.onComplete(result);
+ }
+
+ @Override
+ protected void onCancelled() {
+ if (mCallbacks == null) {
+ return;
+ }
+ mCallbacks.onCancel();
+ }
+
+ /**
+ * Callbacks for the asynchronous task.
+ */
+ public interface Callbacks<P> {
+ void onComplete(Bitmap result);
+
+ void onCancel();
+
+ Bitmap onExecute(P param);
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
index 9c55623d1..30659e677 100644
--- a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
+++ b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
@@ -52,9 +52,6 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
private static final String LOGTAG = "SaveCopyTask";
- private static final int DEFAULT_COMPRESS_QUALITY = 95;
- private static final String DEFAULT_SAVE_DIRECTORY = "EditedOnlinePhotos";
-
/**
* Saves the bitmap in the final destination
*/
@@ -62,7 +59,7 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
OutputStream os = null;
try {
os = new FileOutputStream(destination);
- bitmap.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, os);
+ bitmap.compress(CompressFormat.JPEG, ImageLoader.DEFAULT_COMPRESS_QUALITY, os);
} catch (FileNotFoundException e) {
Log.v(LOGTAG,"Error in writing "+destination.getAbsolutePath());
} finally {
@@ -123,7 +120,7 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
File saveDirectory = getSaveDirectory(context, sourceUri);
if ((saveDirectory == null) || !saveDirectory.canWrite()) {
saveDirectory = new File(Environment.getExternalStorageDirectory(),
- DEFAULT_SAVE_DIRECTORY);
+ ImageLoader.DEFAULT_SAVE_DIRECTORY);
}
// Create the directory if it doesn't exist
if (!saveDirectory.exists()) saveDirectory.mkdirs();
@@ -137,19 +134,6 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
return new File(saveDirectory, filename + ".JPG");
}
- private Bitmap loadMutableBitmap() throws FileNotFoundException {
- BitmapFactory.Options options = new BitmapFactory.Options();
- // TODO: on <3.x we need a copy of the bitmap (inMutable doesn't
- // exist)
- options.inMutable = true;
-
- InputStream is = context.getContentResolver().openInputStream(sourceUri);
- Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
- int orientation = ImageLoader.getOrientation(context, sourceUri);
- bitmap = ImageLoader.rotateToPortrait(bitmap, orientation);
- return bitmap;
- }
-
private static final String[] COPY_EXIF_ATTRIBUTES = new String[] {
ExifInterface.TAG_APERTURE,
ExifInterface.TAG_DATETIME,
@@ -228,7 +212,7 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
ImagePreset preset = params[0];
try {
- Bitmap bitmap = preset.apply(loadMutableBitmap());
+ Bitmap bitmap = preset.apply(ImageLoader.loadMutableBitmap(context, sourceUri));
Object xmp = null;
InputStream is = null;
diff --git a/src/com/android/gallery3d/filtershow/ui/FramedTextButton.java b/src/com/android/gallery3d/filtershow/ui/FramedTextButton.java
index 17453d070..c717b6e61 100644
--- a/src/com/android/gallery3d/filtershow/ui/FramedTextButton.java
+++ b/src/com/android/gallery3d/filtershow/ui/FramedTextButton.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.ImageButton;
@@ -32,6 +33,10 @@ public class FramedTextButton extends ImageButton {
private static int mTextSize = 24;
private static int mTextPadding = 20;
private static Paint gPaint = new Paint();
+ private static Path gPath = new Path();
+ private static int mTrianglePadding = 2;
+ private static int mTriangleSize = 30;
+
private Context mContext = null;
public static void setTextSize(int value) {
@@ -42,6 +47,14 @@ public class FramedTextButton extends ImageButton {
mTextPadding = value;
}
+ public static void setTrianglePadding(int value) {
+ mTrianglePadding = value;
+ }
+
+ public static void setTriangleSize(int value) {
+ mTriangleSize = value;
+ }
+
public void setText(String text) {
mText = text;
invalidate();
@@ -84,11 +97,25 @@ public class FramedTextButton extends ImageButton {
@Override
public void onDraw(Canvas canvas) {
- gPaint.setARGB(255, 255, 255, 255);
+ gPaint.setARGB(96, 255, 255, 255);
gPaint.setStrokeWidth(2);
gPaint.setStyle(Paint.Style.STROKE);
- canvas.drawRect(mTextPadding, mTextPadding, getWidth() - mTextPadding,
- getHeight() - mTextPadding, gPaint);
+ int w = getWidth();
+ int h = getHeight();
+ canvas.drawRect(mTextPadding, mTextPadding, w - mTextPadding,
+ h - mTextPadding, gPaint);
+ gPath.reset();
+ gPath.moveTo(w - mTextPadding - mTrianglePadding - mTriangleSize,
+ h - mTextPadding - mTrianglePadding);
+ gPath.lineTo(w - mTextPadding - mTrianglePadding,
+ h - mTextPadding - mTrianglePadding - mTriangleSize);
+ gPath.lineTo(w - mTextPadding - mTrianglePadding,
+ h - mTextPadding - mTrianglePadding);
+ gPath.close();
+ gPaint.setARGB(128, 255, 255, 255);
+ gPaint.setStrokeWidth(1);
+ gPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ canvas.drawPath(gPath, gPaint);
if (mText != null) {
gPaint.reset();
gPaint.setARGB(255, 255, 255, 255);
@@ -96,8 +123,8 @@ public class FramedTextButton extends ImageButton {
float textWidth = gPaint.measureText(mText);
Rect bounds = new Rect();
gPaint.getTextBounds(mText, 0, mText.length(), bounds);
- int x = (int) ((getWidth() - textWidth) / 2);
- int y = (getHeight() + bounds.height()) / 2;
+ int x = (int) ((w - textWidth) / 2);
+ int y = (h + bounds.height()) / 2;
canvas.drawText(mText, x, y, gPaint);
}
diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
index c4ca900e1..7b04133ce 100644
--- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
+++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
@@ -43,6 +43,7 @@ public class ImageCurves extends ImageSlave {
private boolean mDidAddPoint = false;
private boolean mDidDelete = false;
private ControlPoint mCurrentControlPoint = null;
+ private int mCurrentPick = -1;
private ImagePreset mLastPreset = null;
int[] redHistogram = new int[256];
int[] greenHistogram = new int[256];
@@ -186,6 +187,7 @@ public class ImageCurves extends ImageSlave {
if (e.getActionMasked() == MotionEvent.ACTION_UP) {
mCurrentControlPoint = null;
+ mCurrentPick = -1;
updateCachedImage();
mDidAddPoint = false;
if (mDidDelete) {
@@ -205,8 +207,9 @@ public class ImageCurves extends ImageSlave {
}
Spline spline = getSpline(mCurrentCurveIndex);
- int pick = pickControlPoint(posX, posY);
+ int pick = mCurrentPick;
if (mCurrentControlPoint == null) {
+ pick = pickControlPoint(posX, posY);
if (pick == -1) {
mCurrentControlPoint = new ControlPoint(posX, posY);
pick = spline.addPoint(mCurrentControlPoint);
@@ -214,10 +217,10 @@ public class ImageCurves extends ImageSlave {
} else {
mCurrentControlPoint = spline.getPoint(pick);
}
+ mCurrentPick = pick;
}
if (spline.isPointContained(posX, pick)) {
- spline.didMovePoint(mCurrentControlPoint);
spline.movePoint(pick, posX, posY);
} else if (pick != -1 && spline.getNbPoints() > 2) {
spline.deletePoint(pick);
@@ -275,8 +278,9 @@ public class ImageCurves extends ImageSlave {
max = histogram[i];
}
}
- float w = getWidth();
- float h = getHeight();
+ float w = getWidth() - Spline.curveHandleSize();
+ float h = getHeight() - Spline.curveHandleSize() / 2.0f;
+ float dx = Spline.curveHandleSize() / 2.0f;
float wl = w / histogram.length;
float wh = (0.3f * h) / max;
Paint paint = new Paint();
@@ -288,12 +292,12 @@ public class ImageCurves extends ImageSlave {
paint2.setStrokeWidth(6);
paint2.setXfermode(new PorterDuffXfermode(mode));
gHistoPath.reset();
- gHistoPath.moveTo(0, h);
+ gHistoPath.moveTo(dx, h);
boolean firstPointEncountered = false;
float prev = 0;
float last = 0;
for (int i = 0; i < histogram.length; i++) {
- float x = i * wl;
+ float x = i * wl + dx;
float l = histogram[i] * wh;
if (l != 0) {
float v = h - (l + prev) / 2.0f;
diff --git a/src/com/android/gallery3d/filtershow/ui/Spline.java b/src/com/android/gallery3d/filtershow/ui/Spline.java
index dd9aac1be..83341772b 100644
--- a/src/com/android/gallery3d/filtershow/ui/Spline.java
+++ b/src/com/android/gallery3d/filtershow/ui/Spline.java
@@ -49,7 +49,11 @@ public class Spline {
mPoints = new Vector<ControlPoint>();
for (int i = 0; i < spline.mPoints.size(); i++) {
ControlPoint p = spline.mPoints.elementAt(i);
- mPoints.add(new ControlPoint(p));
+ ControlPoint newPoint = new ControlPoint(p);
+ mPoints.add(newPoint);
+ if (spline.mCurrentControlPoint == p) {
+ mCurrentControlPoint = newPoint;
+ }
}
Collections.sort(mPoints);
}
@@ -79,7 +83,7 @@ public class Spline {
return Color.WHITE;
}
- public void didMovePoint(ControlPoint point) {
+ private void didMovePoint(ControlPoint point) {
mCurrentControlPoint = point;
}
@@ -90,6 +94,7 @@ public class Spline {
ControlPoint point = mPoints.elementAt(pick);
point.x = x;
point.y = y;
+ didMovePoint(point);
}
public boolean isOriginal() {
@@ -121,13 +126,20 @@ public class Spline {
}
double[] derivatives = solveSystem(points);
int start = 0;
+ int end = 256;
if (points[0].x != 0) {
start = (int) (points[0].x * 256);
}
+ if (points[points.length - 1].x != 1) {
+ end = (int) (points[points.length - 1].x * 256);
+ }
for (int i = 0; i < start; i++) {
curve[i] = 1.0f - points[0].y;
}
- for (int i = start; i < 256; i++) {
+ for (int i = end; i < 256; i++) {
+ curve[i] = 1.0f - points[points.length - 1].y;
+ }
+ for (int i = start; i < end; i++) {
ControlPoint cur = null;
ControlPoint next = null;
double x = i / 256.0;