diff options
author | Ruben Brunk <rubenbrunk@google.com> | 2012-11-28 14:00:30 -0800 |
---|---|---|
committer | Ruben Brunk <rubenbrunk@google.com> | 2012-12-06 11:09:27 -0800 |
commit | 6416dd59687768d4152d5d954dd0e8c3617b9d97 (patch) | |
tree | 438c8afac080c9261d3217ea07ad71e2054251fb | |
parent | cc93226fc364a50de3a1479c0912e9af1854b666 (diff) | |
download | android_packages_apps_Gallery2-6416dd59687768d4152d5d954dd0e8c3617b9d97.tar.gz android_packages_apps_Gallery2-6416dd59687768d4152d5d954dd0e8c3617b9d97.tar.bz2 android_packages_apps_Gallery2-6416dd59687768d4152d5d954dd0e8c3617b9d97.zip |
Added support for Crop extras. Wallpaper & Widget use editor crop.
Bug: 7561976
Bug: 7441237
Change-Id: I0d6644171177650568ed911fc63c0c7e104f8d8c
13 files changed, 599 insertions, 68 deletions
diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml index 1f00e8aeb..5659a56ff 100644 --- a/res/values/filtershow_strings.xml +++ b/res/values/filtershow_strings.xml @@ -92,6 +92,8 @@ <string name="aspectNone_effect">None</string> <!-- Label for the aspect None effect [CHAR LIMIT=15] --> <string name="aspectOriginal_effect">@string/original</string> + <!-- Label for when the aspect ratio is fixed to a value [CHAR LIMIT=15] --> + <string name="Fixed">Fixed</string> <!-- Label for the tuny planet effect [CHAR LIMIT=10] --> <string name="tinyplanet">Tiny Planet</string> 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) |