summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRuben Brunk <rubenbrunk@google.com>2012-11-28 14:00:30 -0800
committerRuben Brunk <rubenbrunk@google.com>2012-12-06 11:09:27 -0800
commit6425413690fccb004b52f64b23bc7e3c9cd33e7e (patch)
tree83add395f80f58bdde8ddbd918ede6cf716f48e2 /src
parentb6794369702f20871241e6bff5e6069f27c8d537 (diff)
downloadandroid_packages_apps_Snap-6425413690fccb004b52f64b23bc7e3c9cd33e7e.tar.gz
android_packages_apps_Snap-6425413690fccb004b52f64b23bc7e3c9cd33e7e.tar.bz2
android_packages_apps_Snap-6425413690fccb004b52f64b23bc7e3c9cd33e7e.zip
Added support for Crop extras. Wallpaper & Widget use editor crop.
Bug: 7561976 Bug: 7441237 Change-Id: I0d6644171177650568ed911fc63c0c7e104f8d8c
Diffstat (limited to 'src')
-rw-r--r--src/com/android/gallery3d/app/Wallpaper.java3
-rw-r--r--src/com/android/gallery3d/data/CropExtras.java121
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java129
-rw-r--r--src/com/android/gallery3d/filtershow/PanelController.java11
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java113
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java45
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java25
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java112
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java13
-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/gadget/WidgetConfigure.java3
12 files changed, 597 insertions, 68 deletions
diff --git a/src/com/android/gallery3d/app/Wallpaper.java b/src/com/android/gallery3d/app/Wallpaper.java
index 996d3f080..fce4bacca 100644
--- a/src/com/android/gallery3d/app/Wallpaper.java
+++ b/src/com/android/gallery3d/app/Wallpaper.java
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.view.Display;
import com.android.gallery3d.common.ApiHelper;
+import com.android.gallery3d.filtershow.FilterShowActivity;
/**
* Wallpaper picker for the gallery application. This just redirects to the
@@ -98,7 +99,7 @@ public class Wallpaper extends Activity {
Point size = getDefaultDisplaySize(new Point());
float spotlightX = (float) size.x / width;
float spotlightY = (float) size.y / height;
- Intent request = new Intent(CropImage.ACTION_CROP)
+ Intent request = new Intent(FilterShowActivity.CROP_ACTION)
.setDataAndType(mPickedItem, IMAGE_TYPE)
.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
.putExtra(CropImage.KEY_OUTPUT_X, width)
diff --git a/src/com/android/gallery3d/data/CropExtras.java b/src/com/android/gallery3d/data/CropExtras.java
new file mode 100644
index 000000000..8cec32a34
--- /dev/null
+++ b/src/com/android/gallery3d/data/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.data;
+
+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 a73f44353..9cc3b6ef4 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;
@@ -52,6 +54,7 @@ import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
import android.widget.Toast;
import com.android.gallery3d.R;
+import com.android.gallery3d.data.CropExtras;
import com.android.gallery3d.data.LocalAlbum;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.ImageFilter;
@@ -91,6 +94,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;
@@ -98,9 +102,13 @@ import java.util.Vector;
public class FilterShowActivity extends Activity implements OnItemClickListener,
OnShareTargetSelectedListener {
+ // fields for supporting crop action
public static final String CROP_ACTION = "com.android.camera.action.EDITOR_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;
@@ -405,8 +413,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));
@@ -447,8 +484,9 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
@Override
protected void onProgressUpdate(Boolean... values) {
super.onProgressUpdate(values);
- if (isCancelled())
+ if (isCancelled()) {
return;
+ }
final View filters = findViewById(R.id.filtersPanel);
final View loading = findViewById(R.id.loading);
loading.setVisibility(View.GONE);
@@ -1017,17 +1055,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 872d34a28..dd1c6b4eb 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -56,6 +56,11 @@ 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 mFixedAspect = false;
+
+ public void setFixedAspect(boolean t){
+ mFixedAspect = t;
+ }
class Panel {
private final View mView;
@@ -607,10 +612,12 @@ public class PanelController implements OnClickListener {
mUtilityPanel.setEffectName(ename);
mUtilityPanel.setShowParameter(false);
if (mCurrentImage instanceof ImageCrop && mUtilityPanel.firstTimeCropDisplayed){
- ((ImageCrop) mCurrentImage).applyClear();
+ ((ImageCrop) mCurrentImage).clear();
mUtilityPanel.firstTimeCropDisplayed = false;
}
- mUtilityPanel.showAspectButtons();
+ if (!mFixedAspect){
+ mUtilityPanel.showAspectButtons();
+ }
break;
}
case R.id.rotateButton: {
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index a80c73b1a..0af152cb9 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;
@@ -36,6 +38,7 @@ import com.adobe.xmp.XMPMeta;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.CropExtras;
import com.android.gallery3d.exif.ExifInvalidFormatException;
import com.android.gallery3d.exif.ExifParser;
import com.android.gallery3d.exif.ExifTag;
@@ -44,7 +47,9 @@ 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,6 +58,7 @@ 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;
@@ -73,6 +79,9 @@ public class ImageLoader {
private FilterShowActivity mActivity = null;
+ 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;
@@ -449,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;
}
@@ -468,6 +580,7 @@ public class ImageLoader {
/**
* Determine if this is a light cycle 360 image
+ *
* @return true if it is a light Cycle image that is full 360
*/
public boolean queryLightCycle360() {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
index d74a6faab..2917717f9 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.data.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)
cropBounds = GeometryMath.roundNearest(crop);
- Bitmap temp = null;
- if (mGeometry.hasSwitchedWidthHeight()) {
- temp = Bitmap.createBitmap(cropBounds.height(), cropBounds.width(), mConfig);
- } else {
- temp = Bitmap.createBitmap(cropBounds.width(), cropBounds.height(), mConfig);
+
+ 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/imageshow/GeometryMetadata.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
index 0deb1e1ee..5f32515e7 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
@@ -21,6 +21,7 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
+import com.android.gallery3d.data.CropExtras;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.ImageFilterGeometry;
@@ -38,6 +39,25 @@ public class GeometryMetadata {
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() {
}
@@ -82,6 +102,11 @@ public class GeometryMetadata {
mCropBounds.set(g.mCropBounds);
mPhotoBounds.set(g.mPhotoBounds);
mFlip = g.mFlip;
+
+ mUseCropExtras = g.mUseCropExtras;
+ if (g.mCropExtras != null){
+ mCropExtras = new CropExtras(g.mCropExtras);
+ }
}
public float getScaleFactor() {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
index f25f5b182..84ddaa32d 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
@@ -29,7 +29,7 @@ import android.util.AttributeSet;
import android.util.Log;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.imageshow.ImageGeometry.MODES;
+import com.android.gallery3d.data.CropExtras;
public class ImageCrop extends ImageGeometry {
private static final boolean LOGV = false;
@@ -67,6 +67,8 @@ public class ImageCrop extends ImageGeometry {
private float[] mOffset = {
0, 0
};
+ private CropExtras mCropExtras = null;
+ private boolean mDoingCropIntentAction = false;
private static final String LOGTAG = "ImageCrop";
@@ -103,6 +105,9 @@ public class ImageCrop extends ImageGeometry {
}
private void swapAspect() {
+ if (mDoingCropIntentAction) {
+ return;
+ }
float temp = mAspectWidth;
mAspectWidth = mAspectHeight;
mAspectHeight = temp;
@@ -122,6 +127,14 @@ public class ImageCrop extends ImageGeometry {
mMinSideSize = minHeightWidth;
}
+ public void setExtras(CropExtras e) {
+ mCropExtras = e;
+ }
+
+ public void setCropActionFlag(boolean f) {
+ mDoingCropIntentAction = f;
+ }
+
public void apply(float w, float h) {
mFixAspectRatio = true;
mAspectWidth = w;
@@ -165,6 +178,18 @@ public class ImageCrop extends ImageGeometry {
invalidate();
}
+ public void clear() {
+ if (mCropExtras != null) {
+ int x = mCropExtras.getAspectX();
+ int y = mCropExtras.getAspectY();
+ if (mDoingCropIntentAction && x > 0 && y > 0) {
+ apply(x, y);
+ }
+ } else {
+ applyClear();
+ }
+ }
+
private Matrix getPhotoBoundDisplayedMatrix() {
float[] displayCenter = new float[2];
RectF scaledCrop = new RectF();
@@ -493,7 +518,7 @@ public class ImageCrop extends ImageGeometry {
public void imageLoaded() {
super.imageLoaded();
syncLocalToMasterGeometry();
- applyClear();
+ clear();
invalidate();
}
@@ -549,39 +574,66 @@ public class ImageCrop extends ImageGeometry {
gPaint.setColor(mBorderColor);
gPaint.setStrokeWidth(3);
gPaint.setStyle(Paint.Style.STROKE);
- drawRuleOfThird(canvas, crop, gPaint);
+
+ boolean doThirds = true;
if (mFixAspectRatio) {
- 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);
+ 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;
}
- counter[0] = tempX;
- counter[1] = tempY;
+
+ gPaint.setTextAlign(Paint.Align.CENTER);
+ gPaint.setTextSize(mAspectTextSize);
+ canvas.drawText(mAspect, centX, centY, gPaint);
}
+ }
+
+ if (doThirds) {
+ drawRuleOfThird(canvas, crop, gPaint);
- gPaint.setTextAlign(Paint.Align.CENTER);
- gPaint.setTextSize(mAspectTextSize);
- canvas.drawText(mAspect, centX, centY, gPaint);
}
RectF scaledCrop = crop;
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index fb4a41494..d9df7b7fc 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;
@@ -324,6 +325,10 @@ public class ImageShow extends View implements OnGestureListener,
return dst;
}
+ public Rect getImageCropBounds() {
+ return GeometryMath.roundNearest(getImagePreset().mGeoData.getPreviewCropBounds());
+ }
+
public Rect getDisplayedImageBounds() {
return mImageBounds;
}
@@ -669,6 +674,14 @@ 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);
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/gadget/WidgetConfigure.java b/src/com/android/gallery3d/gadget/WidgetConfigure.java
index 331e7d2c4..b58de7242 100644
--- a/src/com/android/gallery3d/gadget/WidgetConfigure.java
+++ b/src/com/android/gallery3d/gadget/WidgetConfigure.java
@@ -30,6 +30,7 @@ import com.android.gallery3d.app.AlbumPicker;
import com.android.gallery3d.app.CropImage;
import com.android.gallery3d.app.DialogPicker;
import com.android.gallery3d.common.ApiHelper;
+import com.android.gallery3d.filtershow.FilterShowActivity;
public class WidgetConfigure extends Activity {
@SuppressWarnings("unused")
@@ -142,7 +143,7 @@ public class WidgetConfigure extends Activity {
int widgetHeight = Math.round(height * scale);
mPickedItem = data.getData();
- Intent request = new Intent(CropImage.ACTION_CROP, mPickedItem)
+ Intent request = new Intent(FilterShowActivity.CROP_ACTION, mPickedItem)
.putExtra(CropImage.KEY_OUTPUT_X, widgetWidth)
.putExtra(CropImage.KEY_OUTPUT_Y, widgetHeight)
.putExtra(CropImage.KEY_ASPECT_X, widgetWidth)