summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gallerycommon/src/com/android/gallery3d/common/BlobCache.java14
-rw-r--r--gallerycommon/src/com/android/gallery3d/util/ThreadPool.java6
-rw-r--r--src/com/android/gallery3d/app/AbstractGalleryActivity.java1
-rw-r--r--src/com/android/gallery3d/app/AlbumSetPage.java1
-rw-r--r--src/com/android/gallery3d/app/Config.java3
-rw-r--r--src/com/android/gallery3d/app/GalleryActionBar.java9
-rw-r--r--src/com/android/gallery3d/app/OrientationManager.java10
-rw-r--r--src/com/android/gallery3d/app/PhotoPage.java117
-rw-r--r--src/com/android/gallery3d/data/DataManager.java6
-rw-r--r--src/com/android/gallery3d/data/ImageCacheService.java12
-rw-r--r--src/com/android/gallery3d/data/LocalImage.java87
-rw-r--r--src/com/android/gallery3d/data/MediaItem.java8
-rw-r--r--src/com/android/gallery3d/data/MediaObject.java33
-rw-r--r--src/com/android/gallery3d/data/PanoramaMetadataJob.java40
-rw-r--r--src/com/android/gallery3d/data/SecureAlbum.java17
-rw-r--r--src/com/android/gallery3d/data/UriImage.java87
-rw-r--r--src/com/android/gallery3d/filtershow/CenteredLinearLayout.java36
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java216
-rw-r--r--src/com/android/gallery3d/filtershow/PanelController.java111
-rw-r--r--src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java21
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java6
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilter.java15
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java1
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java5
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java128
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java2
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java1
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java2
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java175
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java337
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java54
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java416
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java57
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java21
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageSmallBorder.java2
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java22
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java71
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java34
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePreset.java40
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java2
-rw-r--r--src/com/android/gallery3d/filtershow/ui/ImageButtonTitle.java14
-rw-r--r--src/com/android/gallery3d/filtershow/ui/ImageCurves.java15
-rw-r--r--src/com/android/gallery3d/ui/ActionModeHandler.java4
-rw-r--r--src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java8
-rw-r--r--src/com/android/gallery3d/ui/GLRoot.java3
-rw-r--r--src/com/android/gallery3d/ui/PhotoView.java18
-rw-r--r--src_pd/com/android/gallery3d/util/LightCycleHelper.java23
-rw-r--r--tests/src/com/android/gallery3d/ui/GLRootMock.java2
-rw-r--r--tests/src/com/android/gallery3d/ui/GLRootStub.java2
49 files changed, 1355 insertions, 960 deletions
diff --git a/gallerycommon/src/com/android/gallery3d/common/BlobCache.java b/gallerycommon/src/com/android/gallery3d/common/BlobCache.java
index 7788e61f5..3c131e591 100644
--- a/gallerycommon/src/com/android/gallery3d/common/BlobCache.java
+++ b/gallerycommon/src/com/android/gallery3d/common/BlobCache.java
@@ -74,6 +74,7 @@ import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
+import java.util.Arrays;
import java.util.zip.Adler32;
public class BlobCache implements Closeable {
@@ -379,6 +380,16 @@ public class BlobCache implements Closeable {
updateIndexHeader();
}
+ public void clearEntry(long key) throws IOException {
+ if (!lookupInternal(key, mActiveHashStart)) {
+ return; // Nothing to clear
+ }
+ byte[] header = mBlobHeader;
+ Arrays.fill(header, (byte) 0);
+ mActiveDataFile.seek(mFileOffset);
+ mActiveDataFile.write(header);
+ }
+
// Appends the data to the active file. It also updates the hash entry.
// The proper hash entry (suitable for insertion or replacement) must be
// pointed by mSlotOffset.
@@ -485,6 +496,9 @@ public class BlobCache implements Closeable {
return false;
}
long blobKey = readLong(header, BH_KEY);
+ if (blobKey == 0) {
+ return false; // This entry has been cleared.
+ }
if (blobKey != req.key) {
Log.w(TAG, "blob key does not match: " + blobKey);
return false;
diff --git a/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java b/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java
index cada234b3..115dc6625 100644
--- a/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java
+++ b/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java
@@ -81,8 +81,12 @@ public class ThreadPool {
private final Executor mExecutor;
public ThreadPool() {
+ this(CORE_POOL_SIZE, MAX_POOL_SIZE);
+ }
+
+ public ThreadPool(int initPoolSize, int maxPoolSize) {
mExecutor = new ThreadPoolExecutor(
- CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
+ initPoolSize, maxPoolSize, KEEP_ALIVE_TIME,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
new PriorityThreadFactory("thread-pool",
android.os.Process.THREAD_PRIORITY_BACKGROUND));
diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
index 5e779cd59..cb3aa9d0a 100644
--- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java
+++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
@@ -84,6 +84,7 @@ public class AbstractGalleryActivity extends Activity implements GalleryContext
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
mStateManager.onConfigurationChange(config);
+ getGalleryActionBar().onConfigurationChanged();
invalidateOptionsMenu();
toggleStatusBarByOrientation();
}
diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java
index 1719b89f9..2cb1ca2fa 100644
--- a/src/com/android/gallery3d/app/AlbumSetPage.java
+++ b/src/com/android/gallery3d/app/AlbumSetPage.java
@@ -365,6 +365,7 @@ public class AlbumSetPage extends ActivityState implements
}
private boolean setupCameraButton() {
+ if (!GalleryUtils.isCameraAvailable(mActivity)) return false;
RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity)
.findViewById(R.id.gallery_root);
if (galleryRoot == null) return false;
diff --git a/src/com/android/gallery3d/app/Config.java b/src/com/android/gallery3d/app/Config.java
index 04b210e0e..7183acc33 100644
--- a/src/com/android/gallery3d/app/Config.java
+++ b/src/com/android/gallery3d/app/Config.java
@@ -49,8 +49,7 @@ final class Config {
slotViewSpec.rowsLand = r.getInteger(R.integer.albumset_rows_land);
slotViewSpec.rowsPort = r.getInteger(R.integer.albumset_rows_port);
slotViewSpec.slotGap = r.getDimensionPixelSize(R.dimen.albumset_slot_gap);
- slotViewSpec.slotHeightAdditional = r.getDimensionPixelSize(
- R.dimen.albumset_label_background_height);
+ slotViewSpec.slotHeightAdditional = 0;
paddingTop = r.getDimensionPixelSize(R.dimen.albumset_padding_top);
paddingBottom = r.getDimensionPixelSize(R.dimen.albumset_padding_bottom);
diff --git a/src/com/android/gallery3d/app/GalleryActionBar.java b/src/com/android/gallery3d/app/GalleryActionBar.java
index 1729c6433..f0be01a91 100644
--- a/src/com/android/gallery3d/app/GalleryActionBar.java
+++ b/src/com/android/gallery3d/app/GalleryActionBar.java
@@ -57,6 +57,7 @@ public class GalleryActionBar implements OnNavigationListener {
private AlbumModeAdapter mAlbumModeAdapter;
private OnAlbumModeSelectedListener mAlbumModeListener;
+ private int mLastAlbumModeSelected;
private CharSequence [] mAlbumModes;
public static final int ALBUM_FILMSTRIP_MODE_SELECTED = 0;
public static final int ALBUM_GRID_MODE_SELECTED = 1;
@@ -254,6 +255,13 @@ public class GalleryActionBar implements OnNavigationListener {
}
}
+ public void onConfigurationChanged() {
+ if (mActionBar != null && mAlbumModeListener != null) {
+ OnAlbumModeSelectedListener listener = mAlbumModeListener;
+ enableAlbumModeMenu(mLastAlbumModeSelected, listener);
+ }
+ }
+
public void enableAlbumModeMenu(int selected, OnAlbumModeSelectedListener listener) {
if (mActionBar != null) {
if (mAlbumModeAdapter == null) {
@@ -265,6 +273,7 @@ public class GalleryActionBar implements OnNavigationListener {
mAlbumModeAdapter = new AlbumModeAdapter();
}
mAlbumModeListener = null;
+ mLastAlbumModeSelected = selected;
mActionBar.setListNavigationCallbacks(mAlbumModeAdapter, this);
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
mActionBar.setSelectedNavigationItem(selected);
diff --git a/src/com/android/gallery3d/app/OrientationManager.java b/src/com/android/gallery3d/app/OrientationManager.java
index a8ef99ad8..0e033ebe4 100644
--- a/src/com/android/gallery3d/app/OrientationManager.java
+++ b/src/com/android/gallery3d/app/OrientationManager.java
@@ -98,8 +98,9 @@ public class OrientationManager implements OrientationSource {
public void lockOrientation() {
if (mOrientationLocked) return;
mOrientationLocked = true;
+ int displayRotation = getDisplayRotation();
// Display rotation >= 180 means we need to use the REVERSE landscape/portrait
- boolean standard = getDisplayRotation() < 180;
+ boolean standard = displayRotation < 180;
if (mActivity.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
Log.d(TAG, "lock orientation to landscape");
@@ -107,6 +108,13 @@ public class OrientationManager implements OrientationSource {
? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
: ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
} else {
+ if (displayRotation == 90 || displayRotation == 270) {
+ // If displayRotation = 90 or 270 then we are on a landscape
+ // device. On landscape devices, portrait is a 90 degree
+ // clockwise rotation from landscape, so we need
+ // to flip which portrait we pick as display rotation is counter clockwise
+ standard = !standard;
+ }
Log.d(TAG, "lock orientation to portrait");
mActivity.setRequestedOrientation(standard
? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
index 2e19a2ba8..b11229f88 100644
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -50,6 +50,7 @@ import com.android.gallery3d.data.LocalImage;
import com.android.gallery3d.data.MediaDetails;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.MediaObject;
+import com.android.gallery3d.data.MediaObject.SupportedOperationsListener;
import com.android.gallery3d.data.MediaSet;
import com.android.gallery3d.data.MtpSource;
import com.android.gallery3d.data.Path;
@@ -93,6 +94,9 @@ public class PhotoPage extends ActivityState implements
private static final int MSG_ON_CAMERA_CENTER = 9;
private static final int MSG_ON_PICTURE_CENTER = 10;
private static final int MSG_REFRESH_IMAGE = 11;
+ private static final int MSG_UPDATE_PHOTO_UI = 12;
+ private static final int MSG_UPDATE_PROGRESS = 13;
+ private static final int MSG_UPDATE_DEFERRED = 14;
private static final int HIDE_BARS_TIMEOUT = 3500;
private static final int UNFREEZE_GLROOT_TIMEOUT = 250;
@@ -169,6 +173,10 @@ public class PhotoPage extends ActivityState implements
private boolean mSkipUpdateCurrentPhoto = false;
private static final long CAMERA_SWITCH_CUTOFF_THRESHOLD_MS = 300;
+ private static final long DEFERRED_UPDATE_MS = 150;
+ private boolean mDeferredUpdateWaiting = false;
+ private long mDeferUpdateUntil = Long.MAX_VALUE;
+
private RawTexture mFadeOutTexture;
private Rect mOpenAnimationRect;
public static final int ANIM_TIME_OPENING = 300;
@@ -183,6 +191,21 @@ public class PhotoPage extends ActivityState implements
new MyMenuVisibilityListener();
private UpdateProgressListener mProgressListener;
+ private SupportedOperationsListener mSupportedOperationsListener =
+ new SupportedOperationsListener() {
+ @Override
+ public void onChange(MediaObject item, int operations) {
+ if (item == mCurrentPhoto) {
+ if (mPhotoView.getFilmMode()
+ && SystemClock.uptimeMillis() < mDeferUpdateUntil) {
+ requestDeferredUpdate();
+ } else {
+ mHandler.sendEmptyMessage(MSG_UPDATE_PHOTO_UI);
+ }
+ }
+ }
+ };
+
public static interface Model extends PhotoView.Model {
public void resume();
public void pause();
@@ -209,24 +232,24 @@ public class PhotoPage extends ActivityState implements
@Override
public void onStitchingResult(Uri uri) {
- sendUpdate(uri);
+ sendUpdate(uri, MSG_REFRESH_IMAGE);
}
@Override
public void onStitchingQueued(Uri uri) {
- sendUpdate(uri);
+ sendUpdate(uri, MSG_UPDATE_PROGRESS);
}
@Override
public void onStitchingProgress(Uri uri, final int progress) {
- sendUpdate(uri);
+ sendUpdate(uri, MSG_UPDATE_PROGRESS);
}
- private void sendUpdate(Uri uri) {
+ private void sendUpdate(Uri uri, int message) {
boolean isCurrentPhoto = mCurrentPhoto instanceof LocalImage
&& mCurrentPhoto.getContentUri().equals(uri);
if (isCurrentPhoto) {
- mHandler.sendEmptyMessage(MSG_REFRESH_IMAGE);
+ mHandler.sendEmptyMessage(message);
}
}
};
@@ -314,6 +337,16 @@ public class PhotoPage extends ActivityState implements
mActivity.getGLRoot().unfreeze();
break;
}
+ case MSG_UPDATE_DEFERRED: {
+ long nextUpdate = mDeferUpdateUntil - SystemClock.uptimeMillis();
+ if (nextUpdate <= 0) {
+ mDeferredUpdateWaiting = false;
+ updateUIForCurrentPhoto();
+ } else {
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE_DEFERRED, nextUpdate);
+ }
+ break;
+ }
case MSG_ON_CAMERA_CENTER: {
mSkipUpdateCurrentPhoto = false;
boolean stayedOnCamera = false;
@@ -334,16 +367,24 @@ public class PhotoPage extends ActivityState implements
break;
}
case MSG_ON_PICTURE_CENTER: {
- if (mCurrentPhoto != null
+ if (!mPhotoView.getFilmMode() && mCurrentPhoto != null
&& (mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_ACTION) != 0) {
mPhotoView.setFilmMode(true);
}
break;
}
case MSG_REFRESH_IMAGE: {
- MediaItem currentPhoto = mCurrentPhoto;
+ final MediaItem photo = mCurrentPhoto;
mCurrentPhoto = null;
- updateCurrentPhoto(currentPhoto);
+ updateCurrentPhoto(photo);
+ break;
+ }
+ case MSG_UPDATE_PHOTO_UI: {
+ updateUIForCurrentPhoto();
+ break;
+ }
+ case MSG_UPDATE_PROGRESS: {
+ updateProgressBar();
break;
}
default: throw new AssertionError(message.what);
@@ -452,7 +493,7 @@ public class PhotoPage extends ActivityState implements
int oldIndex = mCurrentIndex;
mCurrentIndex = index;
- if (mAppBridge != null) {
+ if (mInCameraRoll) {
if (mCurrentIndex > 0) {
mSkipUpdateCurrentPhoto = false;
}
@@ -521,6 +562,9 @@ public class PhotoPage extends ActivityState implements
mProgressBar = new PhotoPageProgressBar(mActivity, galleryRoot);
mProgressListener = new UpdateProgressListener();
progressManager.addChangeListener(mProgressListener);
+ if (mSecureAlbum != null) {
+ progressManager.addChangeListener(mSecureAlbum);
+ }
}
}
}
@@ -639,15 +683,21 @@ public class PhotoPage extends ActivityState implements
setNfcBeamPushUri(uri);
}
- private void updateCurrentPhoto(MediaItem photo) {
- if (mCurrentPhoto == photo) return;
- mCurrentPhoto = photo;
+ private void requestDeferredUpdate() {
+ mDeferUpdateUntil = SystemClock.uptimeMillis() + DEFERRED_UPDATE_MS;
+ if (!mDeferredUpdateWaiting) {
+ mDeferredUpdateWaiting = true;
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE_DEFERRED, DEFERRED_UPDATE_MS);
+ }
+ }
+
+ private void updateUIForCurrentPhoto() {
if (mCurrentPhoto == null) return;
// If by swiping or deletion the user ends up on an action item
// and zoomed in, zoom out so that the context of the action is
// more clear
- if ((photo.getSupportedOperations() & MediaObject.SUPPORT_ACTION) != 0
+ if ((mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_ACTION) != 0
&& !mPhotoView.getFilmMode()) {
mPhotoView.setWantPictureCenterCallbacks(true);
}
@@ -658,14 +708,33 @@ public class PhotoPage extends ActivityState implements
mDetailsHelper.reloadDetails();
}
if ((mSecureAlbum == null)
- && (photo.getSupportedOperations() & MediaItem.SUPPORT_SHARE) != 0) {
- updateShareURI(photo.getPath());
+ && (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_SHARE) != 0) {
+ updateShareURI(mCurrentPhoto.getPath());
}
+ updateProgressBar();
+ }
+
+ private void updateCurrentPhoto(MediaItem photo) {
+ if (mCurrentPhoto == photo) return;
+ if (mCurrentPhoto != null) {
+ mCurrentPhoto.setSupportedOperationsListener(null);
+ }
+ mCurrentPhoto = photo;
+ mCurrentPhoto.setSupportedOperationsListener(
+ mSupportedOperationsListener);
+ if (mPhotoView.getFilmMode()) {
+ requestDeferredUpdate();
+ } else {
+ updateUIForCurrentPhoto();
+ }
+ }
+
+ private void updateProgressBar() {
if (mProgressBar != null) {
mProgressBar.hideProgress();
StitchingProgressManager progressManager = mApplication.getStitchingProgressManager();
if (progressManager != null && mCurrentPhoto instanceof LocalImage) {
- Integer progress = progressManager.getProgress(photo.getContentUri());
+ Integer progress = progressManager.getProgress(mCurrentPhoto.getContentUri());
if (progress != null) {
mProgressBar.setProgress(progress);
}
@@ -695,14 +764,18 @@ public class PhotoPage extends ActivityState implements
if ((supportedOperations & MediaObject.SUPPORT_PANORAMA360) != 0) {
mActivity.invalidateOptionsMenu();
item = menu.findItem(R.id.action_share);
- item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- item.setTitle(
- mActivity.getResources().getString(R.string.share_as_photo));
+ if (item != null) {
+ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ item.setTitle(
+ mActivity.getResources().getString(R.string.share_as_photo));
+ }
} else if ((supportedOperations & MediaObject.SUPPORT_SHARE) != 0) {
item = menu.findItem(R.id.action_share);
- item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- item.setTitle(
- mActivity.getResources().getString(R.string.share));
+ if (item != null) {
+ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ item.setTitle(
+ mActivity.getResources().getString(R.string.share));
+ }
}
}
diff --git a/src/com/android/gallery3d/data/DataManager.java b/src/com/android/gallery3d/data/DataManager.java
index 95954e59a..3d2c0c2f0 100644
--- a/src/com/android/gallery3d/data/DataManager.java
+++ b/src/com/android/gallery3d/data/DataManager.java
@@ -250,6 +250,12 @@ public class DataManager {
return getMediaObject(path).getSupportedOperations();
}
+ // getAll will cause this call to wait if any of the operations
+ // are expensive to compute. Do not call in UI thread.
+ public int getSupportedOperations(Path path, boolean getAll) {
+ return getMediaObject(path).getSupportedOperations(getAll);
+ }
+
public void delete(Path path) {
getMediaObject(path).delete();
}
diff --git a/src/com/android/gallery3d/data/ImageCacheService.java b/src/com/android/gallery3d/data/ImageCacheService.java
index 38e32cbee..d42e9521d 100644
--- a/src/com/android/gallery3d/data/ImageCacheService.java
+++ b/src/com/android/gallery3d/data/ImageCacheService.java
@@ -91,6 +91,18 @@ public class ImageCacheService {
}
}
+ public void clearImageData(Path path, int type) {
+ byte[] key = makeKey(path, type);
+ long cacheKey = Utils.crc64Long(key);
+ synchronized (mCache) {
+ try {
+ mCache.clearEntry(cacheKey);
+ } catch (IOException ex) {
+ // ignore.
+ }
+ }
+ }
+
private static byte[] makeKey(Path path, int type) {
return GalleryUtils.getBytes(path.toString() + "+" + type);
}
diff --git a/src/com/android/gallery3d/data/LocalImage.java b/src/com/android/gallery3d/data/LocalImage.java
index 5d6d39dcf..2ba784de7 100644
--- a/src/com/android/gallery3d/data/LocalImage.java
+++ b/src/com/android/gallery3d/data/LocalImage.java
@@ -36,8 +36,11 @@ import com.android.gallery3d.app.GalleryApp;
import com.android.gallery3d.app.StitchingProgressManager;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.BitmapUtils;
+import com.android.gallery3d.util.Future;
+import com.android.gallery3d.util.FutureListener;
import com.android.gallery3d.util.GalleryUtils;
import com.android.gallery3d.util.LightCycleHelper;
+import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata;
import com.android.gallery3d.util.ThreadPool.Job;
import com.android.gallery3d.util.ThreadPool.JobContext;
import com.android.gallery3d.util.UpdateHelper;
@@ -101,11 +104,11 @@ public class LocalImage extends LocalMediaItem {
public int rotation;
- private boolean mUsePanoramaViewer;
- private boolean mUsePanoramaViewerInitialized;
-
- private boolean mIsPanorama360;
- private boolean mIsPanorama360Initialized;
+ private Object mLock = new Object();
+ private Future<PanoramaMetadata> mGetPanoMetadataTask;
+ private boolean mPanoramaMetadataInitialized;
+ private PanoramaMetadata mPanoramaMetadata;
+ private SupportedOperationsListener mListener;
public LocalImage(Path path, GalleryApp application, Cursor cursor) {
super(path, nextVersionNumber());
@@ -255,9 +258,9 @@ public class LocalImage extends LocalMediaItem {
operation |= SUPPORT_SHOW_ON_MAP;
}
- if (usePanoramaViewer()) {
+ if (mPanoramaMetadata != null && mPanoramaMetadata.mUsePanoramaViewer) {
operation |= SUPPORT_PANORAMA;
- if (isPanorama360()) {
+ if (mPanoramaMetadata.mIsPanorama360) {
operation |= SUPPORT_PANORAMA360;
// disable destructive rotate and crop for 360 degree panorama
operation &= ~(SUPPORT_ROTATE | SUPPORT_CROP);
@@ -267,6 +270,53 @@ public class LocalImage extends LocalMediaItem {
}
@Override
+ public int getSupportedOperations(boolean getAll) {
+ synchronized (mLock) {
+ if (getAll && !mPanoramaMetadataInitialized) {
+ if (mGetPanoMetadataTask == null) {
+ mGetPanoMetadataTask = getThreadPool().submit(
+ new PanoramaMetadataJob(mApplication.getAndroidContext(),
+ getContentUri()));
+ }
+ mPanoramaMetadata = mGetPanoMetadataTask.get();
+ mPanoramaMetadataInitialized = true;
+ }
+ }
+ return getSupportedOperations();
+ }
+
+ @Override
+ public void setSupportedOperationsListener(SupportedOperationsListener l) {
+ synchronized (mLock) {
+ if (l == null) {
+ if (mGetPanoMetadataTask != null) {
+ mGetPanoMetadataTask.cancel();
+ mGetPanoMetadataTask = null;
+ }
+ } else {
+ if (mGetPanoMetadataTask == null) {
+ mGetPanoMetadataTask = getThreadPool().submit(
+ new PanoramaMetadataJob(mApplication.getAndroidContext(),
+ getContentUri()),
+ new FutureListener<PanoramaMetadata>() {
+ @Override
+ public void onFutureDone(Future<PanoramaMetadata> future) {
+ mGetPanoMetadataTask = null;
+ if (future.isCancelled()) return;
+ mPanoramaMetadata = future.get();
+ mPanoramaMetadataInitialized = true;
+ if (mListener != null) {
+ mListener.onChange(LocalImage.this, getSupportedOperations());
+ }
+ }
+ });
+ }
+ }
+ mListener = l;
+ }
+ }
+
+ @Override
public void delete() {
GalleryUtils.assertNotInRenderThread();
Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI;
@@ -360,27 +410,4 @@ public class LocalImage extends LocalMediaItem {
public String getFilePath() {
return filePath;
}
-
- @Override
- public boolean usePanoramaViewer() {
- if (!mUsePanoramaViewerInitialized) {
- Context context = mApplication.getAndroidContext();
- mUsePanoramaViewer = LightCycleHelper.hasLightCycleView(context)
- && LightCycleHelper.isPanorama(mApplication.getContentResolver(),
- getContentUri());
- mUsePanoramaViewerInitialized = true;
- }
- return mUsePanoramaViewer;
- }
-
- @Override
- public boolean isPanorama360() {
- // cache flag for faster access
- if (!mIsPanorama360Initialized) {
- mIsPanorama360 = LightCycleHelper.isPanorama360(
- mApplication.getAndroidContext(), getContentUri());
- mIsPanorama360Initialized = true;
- }
- return mIsPanorama360;
- }
}
diff --git a/src/com/android/gallery3d/data/MediaItem.java b/src/com/android/gallery3d/data/MediaItem.java
index da59abeef..19084d41e 100644
--- a/src/com/android/gallery3d/data/MediaItem.java
+++ b/src/com/android/gallery3d/data/MediaItem.java
@@ -103,14 +103,6 @@ public abstract class MediaItem extends MediaObject {
return "";
}
- public boolean usePanoramaViewer() {
- return false;
- }
-
- public boolean isPanorama360() {
- return false;
- }
-
// Returns width and height of the media item.
// Returns 0, 0 if the information is not available.
public abstract int getWidth();
diff --git a/src/com/android/gallery3d/data/MediaObject.java b/src/com/android/gallery3d/data/MediaObject.java
index a16b9666d..14cd5242a 100644
--- a/src/com/android/gallery3d/data/MediaObject.java
+++ b/src/com/android/gallery3d/data/MediaObject.java
@@ -18,6 +18,8 @@ package com.android.gallery3d.data;
import android.net.Uri;
+import com.android.gallery3d.util.ThreadPool;
+
public abstract class MediaObject {
@SuppressWarnings("unused")
private static final String TAG = "MediaObject";
@@ -37,14 +39,20 @@ public abstract class MediaObject {
public static final int SUPPORT_INFO = 1 << 10;
public static final int SUPPORT_IMPORT = 1 << 11;
public static final int SUPPORT_TRIM = 1 << 12;
- public static final int SUPPORT_PANORAMA = 1 << 13;
- public static final int SUPPORT_PANORAMA360 = 1 << 14;
- public static final int SUPPORT_UNLOCK = 1 << 15;
- public static final int SUPPORT_BACK = 1 << 16;
- public static final int SUPPORT_ACTION = 1 << 17;
- public static final int SUPPORT_CAMERA_SHORTCUT = 1 << 18;
+ public static final int SUPPORT_UNLOCK = 1 << 13;
+ public static final int SUPPORT_BACK = 1 << 14;
+ public static final int SUPPORT_ACTION = 1 << 15;
+ public static final int SUPPORT_CAMERA_SHORTCUT = 1 << 16;
+ // The panorama specific bits are expensive to compute.
+ // Use SupportedOperationsListener to request them.
+ public static final int SUPPORT_PANORAMA = 1 << 30;
+ public static final int SUPPORT_PANORAMA360 = 1 << 31;
public static final int SUPPORT_ALL = 0xffffffff;
+ public static interface SupportedOperationsListener {
+ public void onChange(MediaObject item, int operations);
+ }
+
// These are the bits returned from getMediaType():
public static final int MEDIA_TYPE_UNKNOWN = 1;
public static final int MEDIA_TYPE_IMAGE = 2;
@@ -72,6 +80,11 @@ public abstract class MediaObject {
protected final Path mPath;
+ private static ThreadPool sThreadPool = new ThreadPool(1, 1);
+ public static ThreadPool getThreadPool() {
+ return sThreadPool;
+ }
+
public MediaObject(Path path, long version) {
path.setObject(this);
mPath = path;
@@ -86,6 +99,14 @@ public abstract class MediaObject {
return 0;
}
+ public int getSupportedOperations(boolean getAll) {
+ return getSupportedOperations();
+ }
+
+ public void setSupportedOperationsListener(SupportedOperationsListener l) {
+ // nothing to do
+ }
+
public void delete() {
throw new UnsupportedOperationException();
}
diff --git a/src/com/android/gallery3d/data/PanoramaMetadataJob.java b/src/com/android/gallery3d/data/PanoramaMetadataJob.java
new file mode 100644
index 000000000..e0a69c41f
--- /dev/null
+++ b/src/com/android/gallery3d/data/PanoramaMetadataJob.java
@@ -0,0 +1,40 @@
+/*
+ * 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.content.Context;
+import android.net.Uri;
+
+import com.android.gallery3d.util.LightCycleHelper;
+import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata;
+import com.android.gallery3d.util.ThreadPool.Job;
+import com.android.gallery3d.util.ThreadPool.JobContext;
+
+class PanoramaMetadataJob implements Job<PanoramaMetadata> {
+ Context mContext;
+ Uri mUri;
+
+ public PanoramaMetadataJob(Context context, Uri uri) {
+ mContext = context;
+ mUri = uri;
+ }
+
+ @Override
+ public PanoramaMetadata run(JobContext jc) {
+ return LightCycleHelper.getPanoramaMetadata(mContext, mUri);
+ }
+}
diff --git a/src/com/android/gallery3d/data/SecureAlbum.java b/src/com/android/gallery3d/data/SecureAlbum.java
index c666bdc75..0a8c5a827 100644
--- a/src/com/android/gallery3d/data/SecureAlbum.java
+++ b/src/com/android/gallery3d/data/SecureAlbum.java
@@ -24,12 +24,13 @@ import android.provider.MediaStore.MediaColumns;
import android.provider.MediaStore.Video;
import com.android.gallery3d.app.GalleryApp;
+import com.android.gallery3d.app.StitchingChangeListener;
import com.android.gallery3d.util.MediaSetUtils;
import java.util.ArrayList;
// This class lists all media items added by the client.
-public class SecureAlbum extends MediaSet {
+public class SecureAlbum extends MediaSet implements StitchingChangeListener {
@SuppressWarnings("unused")
private static final String TAG = "SecureAlbum";
private static final String[] PROJECTION = {MediaColumns._ID};
@@ -183,4 +184,18 @@ public class SecureAlbum extends MediaSet {
public boolean isLeafAlbum() {
return true;
}
+
+ @Override
+ public void onStitchingQueued(Uri uri) {
+ int id = Integer.parseInt(uri.getLastPathSegment());
+ addMediaItem(false, id);
+ }
+
+ @Override
+ public void onStitchingResult(Uri uri) {
+ }
+
+ @Override
+ public void onStitchingProgress(Uri uri, final int progress) {
+ }
}
diff --git a/src/com/android/gallery3d/data/UriImage.java b/src/com/android/gallery3d/data/UriImage.java
index b2cbc7d68..aaa36a917 100644
--- a/src/com/android/gallery3d/data/UriImage.java
+++ b/src/com/android/gallery3d/data/UriImage.java
@@ -28,7 +28,10 @@ import android.os.ParcelFileDescriptor;
import com.android.gallery3d.app.GalleryApp;
import com.android.gallery3d.common.BitmapUtils;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.util.Future;
+import com.android.gallery3d.util.FutureListener;
import com.android.gallery3d.util.LightCycleHelper;
+import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata;
import com.android.gallery3d.util.ThreadPool.CancelListener;
import com.android.gallery3d.util.ThreadPool.Job;
import com.android.gallery3d.util.ThreadPool.JobContext;
@@ -56,10 +59,12 @@ public class UriImage extends MediaItem {
private int mWidth;
private int mHeight;
private int mRotation;
- private boolean mUsePanoramaViewer;
- private boolean mUsePanoramaViewerInitialized;
- private boolean mIsPanorama360;
- private boolean mIsPanorama360Initialized;
+
+ private Object mLock = new Object();
+ private Future<PanoramaMetadata> mGetPanoMetadataTask;
+ private boolean mPanoramaMetadataInitialized;
+ private PanoramaMetadata mPanoramaMetadata;
+ private SupportedOperationsListener mListener;
private GalleryApp mApplication;
@@ -220,9 +225,9 @@ public class UriImage extends MediaItem {
if (BitmapUtils.isSupportedByRegionDecoder(mContentType)) {
supported |= SUPPORT_FULL_IMAGE;
}
- if (usePanoramaViewer()) {
+ if (mPanoramaMetadata != null && mPanoramaMetadata.mUsePanoramaViewer) {
supported |= SUPPORT_PANORAMA;
- if (isPanorama360()) {
+ if (mPanoramaMetadata.mIsPanorama360) {
supported |= SUPPORT_PANORAMA360;
// disable destructive crop for 360 degree panorama
supported &= ~SUPPORT_CROP;
@@ -231,6 +236,53 @@ public class UriImage extends MediaItem {
return supported;
}
+ @Override
+ public int getSupportedOperations(boolean getAll) {
+ synchronized (mLock) {
+ if (getAll && !mPanoramaMetadataInitialized) {
+ if (mGetPanoMetadataTask == null) {
+ mGetPanoMetadataTask = getThreadPool().submit(
+ new PanoramaMetadataJob(mApplication.getAndroidContext(),
+ getContentUri()));
+ }
+ mPanoramaMetadata = mGetPanoMetadataTask.get();
+ mPanoramaMetadataInitialized = true;
+ }
+ }
+ return getSupportedOperations();
+ }
+
+ @Override
+ public void setSupportedOperationsListener(SupportedOperationsListener l) {
+ synchronized (mLock) {
+ if (l != null) {
+ if (mGetPanoMetadataTask != null) {
+ mGetPanoMetadataTask.cancel();
+ mGetPanoMetadataTask = null;
+ }
+ } else {
+ if (mGetPanoMetadataTask == null) {
+ mGetPanoMetadataTask = getThreadPool().submit(
+ new PanoramaMetadataJob(mApplication.getAndroidContext(),
+ getContentUri()),
+ new FutureListener<PanoramaMetadata>() {
+ @Override
+ public void onFutureDone(Future<PanoramaMetadata> future) {
+ mGetPanoMetadataTask = null;
+ if (future.isCancelled()) return;
+ mPanoramaMetadata = future.get();
+ mPanoramaMetadataInitialized = true;
+ if (mListener != null) {
+ mListener.onChange(UriImage.this, getSupportedOperations());
+ }
+ }
+ });
+ }
+ }
+ mListener = l;
+ }
+ }
+
private boolean isSharable() {
// We cannot grant read permission to the receiver since we put
// the data URI in EXTRA_STREAM instead of the data part of an intent
@@ -297,27 +349,4 @@ public class UriImage extends MediaItem {
public int getRotation() {
return mRotation;
}
-
- @Override
- public boolean usePanoramaViewer() {
- if (!mUsePanoramaViewerInitialized) {
- Context context = mApplication.getAndroidContext();
- mUsePanoramaViewer = LightCycleHelper.hasLightCycleView(context)
- && LightCycleHelper.isPanorama(mApplication.getContentResolver(),
- getContentUri());
- mUsePanoramaViewerInitialized = true;
- }
- return mUsePanoramaViewer;
- }
-
- @Override
- public boolean isPanorama360() {
- // cache flag for faster access
- if (!mIsPanorama360Initialized) {
- mIsPanorama360 = LightCycleHelper.isPanorama360(
- mApplication.getAndroidContext(), getContentUri());
- mIsPanorama360Initialized = true;
- }
- return mIsPanorama360;
- }
}
diff --git a/src/com/android/gallery3d/filtershow/CenteredLinearLayout.java b/src/com/android/gallery3d/filtershow/CenteredLinearLayout.java
new file mode 100644
index 000000000..16b969535
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/CenteredLinearLayout.java
@@ -0,0 +1,36 @@
+package com.android.gallery3d.filtershow;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View.MeasureSpec;
+import android.widget.LinearLayout;
+
+import com.android.gallery3d.R;
+
+public class CenteredLinearLayout extends LinearLayout {
+ private final int mMaxWidth;
+
+ public CenteredLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CenteredLinearLayout);
+ mMaxWidth = a.getDimensionPixelSize(R.styleable.CenteredLinearLayout_max_width, 0);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
+ int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
+ Resources r = getContext().getResources();
+ float value = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, parentWidth,
+ r.getDisplayMetrics());
+ if (mMaxWidth > 0 && parentWidth > mMaxWidth) {
+ int measureMode = MeasureSpec.getMode(widthMeasureSpec);
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, measureMode);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index f204e4020..fbec411e3 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -11,17 +11,18 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
+import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
@@ -35,8 +36,17 @@ import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
+import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
+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.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.ImageFilterVibrance;
+import com.android.gallery3d.filtershow.filters.ImageFilterVignette;
+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;
@@ -45,18 +55,12 @@ 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.ImageWithIcon;
import com.android.gallery3d.filtershow.imageshow.ImageZoom;
import com.android.gallery3d.filtershow.presets.ImagePreset;
-import com.android.gallery3d.filtershow.presets.ImagePresetBW;
-import com.android.gallery3d.filtershow.presets.ImagePresetBWBlue;
-import com.android.gallery3d.filtershow.presets.ImagePresetBWGreen;
-import com.android.gallery3d.filtershow.presets.ImagePresetBWRed;
-import com.android.gallery3d.filtershow.presets.ImagePresetFX;
-import com.android.gallery3d.filtershow.presets.ImagePresetOld;
-import com.android.gallery3d.filtershow.presets.ImagePresetSaturated;
-import com.android.gallery3d.filtershow.presets.ImagePresetXProcessing;
import com.android.gallery3d.filtershow.provider.SharedImageProvider;
import com.android.gallery3d.filtershow.tools.SaveCopyTask;
+import com.android.gallery3d.filtershow.ui.ImageButtonTitle;
import com.android.gallery3d.filtershow.ui.ImageCurves;
import java.io.File;
@@ -93,6 +97,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
private static final int SELECT_PICTURE = 1;
private static final String LOGTAG = "FilterShowActivity";
protected static final boolean ANIMATE_PANELS = true;
+ private static int mImageBorderSize = 40;
private boolean mShowingHistoryPanel = false;
private boolean mShowingImageStatePanel = false;
@@ -114,6 +119,15 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
ImageFilterRS.setRenderScriptContext(this);
+ // TODO: get those values from XML.
+ ImageShow.setTextSize((int) getPixelsFromDip(12));
+ ImageShow.setTextPadding((int) getPixelsFromDip(10));
+ ImageButtonTitle.setTextSize((int) getPixelsFromDip(12));
+ ImageButtonTitle.setTextPadding((int) getPixelsFromDip(10));
+ ImageSmallFilter.setMargin((int) getPixelsFromDip(6));
+ ImageSmallFilter.setTextMargin((int) getPixelsFromDip(4));
+ mImageBorderSize = (int) getPixelsFromDip(20);
+
setContentView(R.layout.filtershow_activity);
ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
@@ -130,6 +144,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
LinearLayout listFilters = (LinearLayout) findViewById(R.id.listFilters);
LinearLayout listBorders = (LinearLayout) findViewById(R.id.listBorders);
+ LinearLayout listColors = (LinearLayout) findViewById(R.id.listColorsFx);
mImageShow = (ImageShow) findViewById(R.id.imageShow);
mImageCurves = (ImageCurves) findViewById(R.id.imageCurves);
@@ -200,7 +215,84 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton));
mPanelController.addPanel(mColorsButton, mListColors, 3);
- mPanelController.addComponent(mColorsButton, findViewById(R.id.vignetteButton));
+
+ int []recastIDs = {
+ R.id.vignetteButton,
+ R.id.vibranceButton,
+ R.id.contrastButton,
+ R.id.saturationButton,
+ R.id.wbalanceButton,
+ R.id.hueButton,
+ R.id.exposureButton,
+ R.id.shadowRecoveryButton
+ };
+ ImageFilter []filters = {
+ new ImageFilterVignette(),
+ new ImageFilterVibrance(),
+ new ImageFilterContrast(),
+ new ImageFilterSaturated(),
+ new ImageFilterWBalance(),
+ new ImageFilterHue(),
+ new ImageFilterExposure(),
+ new ImageFilterShadows()
+ };
+
+
+ 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(100);
+ 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.sharpen,
+ 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]);
+
+ mPanelController.addComponent(mColorsButton, fView);
+ listColors.addView(fView,pos);
+ }
+
mPanelController.addComponent(mColorsButton, findViewById(R.id.curvesButtonRGB));
mPanelController.addComponent(mColorsButton, findViewById(R.id.sharpenButton));
mPanelController.addComponent(mColorsButton, findViewById(R.id.vibranceButton));
@@ -211,12 +303,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mPanelController.addComponent(mColorsButton, findViewById(R.id.exposureButton));
mPanelController.addComponent(mColorsButton, findViewById(R.id.shadowRecoveryButton));
- mPanelController.addView(findViewById(R.id.resetEffect));
mPanelController.addView(findViewById(R.id.applyEffect));
- findViewById(R.id.compareWithOriginalImage).setOnTouchListener(
- createOnTouchShowOriginalButton());
-
findViewById(R.id.resetOperationsButton).setOnClickListener(
createOnClickResetOperationsButton());
@@ -236,7 +324,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mImageZoom.setSeekBar(seekBar);
mPanelController.setRowPanel(findViewById(R.id.secondRowPanel));
mPanelController.setUtilityPanel(this, findViewById(R.id.filterButtonsList),
- findViewById(R.id.compareWithOriginalImage),
findViewById(R.id.applyEffect));
mPanelController.setMasterImage(mImageShow);
mPanelController.setCurrentPanel(mFxButton);
@@ -244,12 +331,22 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
String data = intent.getDataString();
if (data != null) {
Uri uri = Uri.parse(data);
- mImageLoader.loadBitmap(uri);
+ mImageLoader.loadBitmap(uri,getScreenImageSize());
} else {
pickImage();
}
}
+ private int getScreenImageSize(){
+ DisplayMetrics metrics = new DisplayMetrics();
+ Display display = getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ display.getMetrics(metrics);
+ int msize = Math.min(size.x, size.y);
+ return (133*msize)/metrics.densityDpi;
+ }
+
private void showSavingProgress() {
ProgressDialog progress;
if (mSavingProgressDialog != null) {
@@ -397,7 +494,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
private void fillListImages(LinearLayout listFilters) {
// TODO: use listview
// TODO: load the filters straight from the filesystem
- ImagePreset[] preset = new ImagePreset[18];
+
+ ImageFilterFx[] fxArray = new ImageFilterFx[18];
int p = 0;
int[] drawid = {
@@ -424,25 +522,34 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
R.string.ffx_washout_color,
};
- preset[p++] = new ImagePreset();
+ ImagePreset preset = new ImagePreset(); // empty
+ ImageSmallFilter filter = new ImageSmallFilter(this);
+
+ filter.setSelected(true);
+ mCurrentImageSmallFilter = filter;
+
+ filter.setPreviousImageSmallFilter(null);
+ preset.setIsFx(true);
+ filter.setImagePreset(preset);
+
+ filter.setController(this);
+ filter.setImageLoader(mImageLoader);
+ listFilters.addView(filter);
+ ImageSmallFilter previousFilter = filter;
+
BitmapFactory.Options o = new BitmapFactory.Options();
o.inScaled = false;
for (int i = 0; i < drawid.length; i++) {
Bitmap b = BitmapFactory.decodeResource(getResources(), drawid[i], o);
- preset[p++] = new ImagePresetFX(b, getString(fxNameid[i]));
+ fxArray[p++] = new ImageFilterFx(b, getString(fxNameid[i]));
}
- ImageSmallFilter previousFilter = null;
for (int i = 0; i < p; i++) {
- ImageSmallFilter filter = new ImageSmallFilter(this);
- if (i == 0) {
- filter.setSelected(true);
- mCurrentImageSmallFilter = filter;
- }
+ filter = new ImageSmallFilter(this);
+
filter.setPreviousImageSmallFilter(previousFilter);
- preset[i].setIsFx(true);
- filter.setImagePreset(preset[i]);
+ filter.setImageFilter(fxArray[i]);
filter.setController(this);
filter.setImageLoader(mImageLoader);
listFilters.addView(filter);
@@ -450,7 +557,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
}
// Default preset (original)
- mImageShow.setImagePreset(preset[0]);
+ mImageShow.setImagePreset(preset);
}
private void fillListBorders(LinearLayout listBorders) {
@@ -460,15 +567,14 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
ImageFilter[] borders = new ImageFilter[7];
borders[p++] = new ImageFilterBorder(null);
- Drawable npd3 = getResources().getDrawable(R.drawable.filtershow_border_film3);
- borders[p++] = new ImageFilterBorder(npd3);
- Drawable npd = getResources().getDrawable(
- R.drawable.filtershow_border_scratch3);
- borders[p++] = new ImageFilterBorder(npd);
- borders[p++] = new ImageFilterParametricBorder(Color.BLACK, 100, 0);
- borders[p++] = new ImageFilterParametricBorder(Color.BLACK, 100, 100);
- borders[p++] = new ImageFilterParametricBorder(Color.WHITE, 100, 0);
- borders[p++] = new ImageFilterParametricBorder(Color.WHITE, 100, 100);
+ 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);
+ 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);
ImageSmallFilter previousFilter = null;
for (int i = 0; i < p; i++) {
@@ -526,23 +632,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
}
}
- // //////////////////////////////////////////////////////////////////////////////
- // Click handlers for the top row buttons
-
- private OnTouchListener createOnTouchShowOriginalButton() {
- return new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- boolean show = false;
- if ((event.getActionMasked() != MotionEvent.ACTION_UP)
- || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
- show = true;
- }
- showOriginalViews(show);
- return true;
- }
- };
- }
// //////////////////////////////////////////////////////////////////////////////
// imageState panel...
@@ -629,6 +718,12 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
};
}
+ @Override
+ public void onBackPressed() {
+ if (mPanelController.onBackPressed()) {
+ finish();
+ }
+ }
// //////////////////////////////////////////////////////////////////////////////
public float getPixelsFromDip(float value) {
@@ -672,12 +767,9 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
ImagePreset oldPreset = mImageShow.getImagePreset();
ImagePreset copy = new ImagePreset(oldPreset);
// TODO: use a numerical constant instead.
- if (setBorder) {
- copy.setHistoryName("Border");
- copy.setBorder(imageFilter);
- } else {
- copy.add(imageFilter);
- }
+
+ copy.add(imageFilter);
+
mImageShow.setImagePreset(copy);
invalidateViews();
}
@@ -703,7 +795,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
- mImageLoader.loadBitmap(selectedImageUri);
+ mImageLoader.loadBitmap(selectedImageUri,getScreenImageSize());
}
}
}
diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java
index 8da762559..963d17a6f 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -108,17 +108,15 @@ public class PanelController implements OnClickListener {
class UtilityPanel {
private final Context mContext;
private final View mView;
- private final View mCompareView;
private final TextView mTextView;
private boolean mSelected = false;
private String mEffectName = null;
private int mParameterValue = 0;
private boolean mShowParameterValue = false;
- public UtilityPanel(Context context, View view, View compareView, View textView) {
+ public UtilityPanel(Context context, View view, View textView) {
mContext = context;
mView = view;
- mCompareView = compareView;
mTextView = (TextView) textView;
}
@@ -131,31 +129,23 @@ public class PanelController implements OnClickListener {
updateText();
}
- public void setGeometryEffect(boolean isGeometryEffect) {
- if (isGeometryEffect) {
- mCompareView.setVisibility(View.INVISIBLE);
- } else {
- mCompareView.setVisibility(View.VISIBLE);
- }
- }
-
public void setEffectName(String effectName) {
mEffectName = effectName;
- showParameter(true);
- updateText();
+ setShowParameter(true);
}
- public void showParameter(boolean s) {
+ public void setShowParameter(boolean s) {
mShowParameterValue = s;
+ updateText();
}
public void updateText() {
String apply = mContext.getString(R.string.apply_effect);
if (mShowParameterValue) {
- mTextView.setText(Html.fromHtml(apply + "<br/><small>" + mEffectName + "<br/>"
- + mParameterValue + "</small>"));
+ mTextView.setText(Html.fromHtml(apply + " " + mEffectName + " "
+ + mParameterValue));
} else {
- mTextView.setText(Html.fromHtml(apply + "<br/><small>" + mEffectName + "</small>"));
+ mTextView.setText(Html.fromHtml(apply + " " + mEffectName));
}
}
@@ -239,12 +229,22 @@ public class PanelController implements OnClickListener {
imageShow.setPanelController(this);
}
+ public boolean onBackPressed() {
+ if (mUtilityPanel == null || !mUtilityPanel.selected()) {
+ return true;
+ }
+ mCurrentImage.resetParameter();
+ showPanel(mCurrentPanel);
+ mCurrentImage.select();
+ return false;
+ }
+
public void onNewValue(int value) {
mUtilityPanel.onNewValue(value);
}
public void showParameter(boolean s) {
- mUtilityPanel.showParameter(s);
+ mUtilityPanel.setShowParameter(s);
}
public void setCurrentPanel(View panel) {
@@ -255,8 +255,8 @@ public class PanelController implements OnClickListener {
mRowPanel = rowPanel;
}
- public void setUtilityPanel(Context context, View utilityPanel, View compareView, View textView) {
- mUtilityPanel = new UtilityPanel(context, utilityPanel, compareView, textView);
+ public void setUtilityPanel(Context context, View utilityPanel, View textView) {
+ mUtilityPanel = new UtilityPanel(context, utilityPanel, textView);
}
public void setMasterImage(ImageShow imageShow) {
@@ -337,7 +337,6 @@ public class PanelController implements OnClickListener {
public ImageFilter setImagePreset(ImageFilter filter, String name) {
ImagePreset copy = new ImagePreset(getImagePreset());
copy.add(filter);
- copy.setHistoryName(filter.getName());
copy.setIsFx(false);
mMasterImage.setImagePreset(copy);
return filter;
@@ -397,41 +396,42 @@ public class PanelController implements OnClickListener {
switch (view.getId()) {
case R.id.straightenButton: {
mCurrentImage = showImageView(R.id.imageStraighten);
- mUtilityPanel.setEffectName("Straighten");
- mUtilityPanel.setGeometryEffect(true);
+ String ename = mCurrentImage.getContext().getString(R.string.straighten);
+ mUtilityPanel.setEffectName(ename);
break;
}
case R.id.cropButton: {
mCurrentImage = showImageView(R.id.imageCrop);
- mUtilityPanel.setEffectName("Crop");
- mUtilityPanel.showParameter(false);
- mUtilityPanel.setGeometryEffect(true);
+ String ename = mCurrentImage.getContext().getString(R.string.crop);
+ mUtilityPanel.setEffectName(ename);
+ mUtilityPanel.setShowParameter(false);
break;
}
case R.id.rotateButton: {
mCurrentImage = showImageView(R.id.imageRotate);
- mUtilityPanel.setEffectName("Rotate");
- mUtilityPanel.setGeometryEffect(true);
+ String ename = mCurrentImage.getContext().getString(R.string.rotate);
+ mUtilityPanel.setEffectName(ename);
break;
}
case R.id.flipButton: {
mCurrentImage = showImageView(R.id.imageFlip);
- mUtilityPanel.setEffectName("Flip");
- mUtilityPanel.showParameter(false);
- mUtilityPanel.setGeometryEffect(true);
+ String ename = mCurrentImage.getContext().getString(R.string.flip);
+ mUtilityPanel.setEffectName(ename);
+ mUtilityPanel.setShowParameter(false);
break;
}
case R.id.vignetteButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Vignette");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.vignette);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Vignette");
break;
}
case R.id.curvesButtonRGB: {
ImageCurves curves = (ImageCurves) showImageView(R.id.imageCurves);
- mUtilityPanel.setEffectName("Curves");
- mUtilityPanel.setGeometryEffect(true);
+ String ename = curves.getContext().getString(R.string.curvesRGB);
+ mUtilityPanel.setEffectName(ename);
+ mUtilityPanel.setShowParameter(false);
curves.setUseRed(true);
curves.setUseGreen(true);
curves.setUseBlue(true);
@@ -441,71 +441,68 @@ public class PanelController implements OnClickListener {
}
case R.id.sharpenButton: {
mCurrentImage = showImageView(R.id.imageZoom).setShowControls(true);
- mUtilityPanel.setEffectName("Sharpen");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.sharpen);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Sharpen");
break;
}
case R.id.contrastButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Contrast");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.contrast);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Contrast");
break;
}
case R.id.saturationButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Saturated");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.saturation);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Saturated");
break;
}
case R.id.wbalanceButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(false);
- mUtilityPanel.setEffectName("White Balance");
- mUtilityPanel.setGeometryEffect(true);
+ String ename = mCurrentImage.getContext().getString(R.string.wbalance);
+ mUtilityPanel.setEffectName(ename);
+ mUtilityPanel.setShowParameter(false);
ensureFilter("WBalance");
break;
}
case R.id.hueButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Hue");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.hue);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Hue");
break;
}
case R.id.exposureButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Exposure");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.exposure);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Exposure");
break;
}
case R.id.vibranceButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Vibrance");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.vibrance);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Vibrance");
break;
}
case R.id.shadowRecoveryButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Shadows");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.shadow_recovery);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Shadows");
break;
}
case R.id.redEyeButton: {
mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
- mUtilityPanel.setEffectName("Redeye");
- mUtilityPanel.setGeometryEffect(false);
+ String ename = mCurrentImage.getContext().getString(R.string.redeye);
+ mUtilityPanel.setEffectName(ename);
ensureFilter("Redeye");
break;
}
- case R.id.resetEffect: {
- mCurrentImage.resetParameter();
- break;
- }
case R.id.applyEffect: {
showPanel(mCurrentPanel);
break;
diff --git a/src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java b/src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java
index 67bd49b1c..25d1db414 100644
--- a/src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java
+++ b/src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java
@@ -62,7 +62,7 @@ public class DirectPresetCache implements Cache {
private CachedPreset getCachedPreset(ImagePreset preset) {
for (int i = 0; i < mCache.size(); i++) {
CachedPreset cache = mCache.elementAt(i);
- if (cache.mPreset == preset && !cache.mBusy) {
+ if (cache.mPreset == preset) {
return cache;
}
}
@@ -73,7 +73,7 @@ public class DirectPresetCache implements Cache {
public Bitmap get(ImagePreset preset) {
// Log.v(LOGTAG, "get preset " + preset.name() + " : " + preset);
CachedPreset cache = getCachedPreset(preset);
- if (cache != null) {
+ if (cache != null && !cache.mBusy) {
return cache.mBitmap;
}
// Log.v(LOGTAG, "didn't find preset " + preset.name() + " : " + preset
@@ -138,18 +138,21 @@ public class DirectPresetCache implements Cache {
public void prepare(ImagePreset preset) {
// Log.v(LOGTAG, "prepare preset " + preset.name() + " : " + preset);
CachedPreset cache = getCachedPreset(preset);
- if (cache == null) {
- if (mCache.size() < mCacheSize) {
- cache = new CachedPreset();
- mCache.add(cache);
- } else {
- cache = getOldestCachedPreset();
+ if (cache == null || (cache.mBitmap == null && !cache.mBusy)) {
+ if (cache == null) {
+ if (mCache.size() < mCacheSize) {
+ cache = new CachedPreset();
+ mCache.add(cache);
+ } else {
+ cache = getOldestCachedPreset();
+ }
}
if (cache != null) {
cache.mPreset = preset;
+ willCompute(cache);
}
}
- willCompute(cache);
+
}
}
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 54d71ad77..e00a1b77d 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -61,11 +61,12 @@ public class ImageLoader {
mHiresCache = new DelayedPresetCache(this, 2);
}
- public void loadBitmap(Uri uri) {
+ public void loadBitmap(Uri uri,int size) {
mUri = uri;
mOrientation = getOrientation(uri);
+
mOriginalBitmapSmall = loadScaledBitmap(uri, 160);
- mOriginalBitmapLarge = loadScaledBitmap(uri, 320);
+ mOriginalBitmapLarge = loadScaledBitmap(uri, size);
updateBitmaps();
}
@@ -179,6 +180,7 @@ public class ImageLoader {
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
+
closeStream(is);
is = mContext.getContentResolver().openInputStream(uri);
return BitmapFactory.decodeStream(is, null, o2);
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index 662e8ed2b..6d0c020a7 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -8,12 +8,27 @@ public class ImageFilter implements Cloneable {
protected int mParameter = 0;
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_WBALANCE = 3;
+ public static final byte TYPE_VIGNETTE = 4;
+ public static final byte TYPE_NORMAL = 5;
+ private byte filterType = TYPE_NORMAL;
+
+ public byte getFilterType(){
+ return filterType;
+ }
+
+ protected void setFilterType(byte type){
+ filterType = type;
+ }
@Override
public ImageFilter clone() throws CloneNotSupportedException {
ImageFilter filter = (ImageFilter) super.clone();
filter.setName(getName());
filter.setParameter(getParameter());
+ filter.setFilterType(filterType);
return filter;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
index 9fcf1dc1d..dd7d17c46 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
@@ -17,6 +17,7 @@ public class ImageFilterBorder extends ImageFilter {
}
public ImageFilterBorder(Drawable ninePatch) {
+ setFilterType(TYPE_BORDER);
mName = "Border";
mNinePatch = ninePatch;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java
index 00fd20cf5..1575b18bb 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java
@@ -13,8 +13,9 @@ public class ImageFilterFx extends ImageFilter {
private static final String TAG = "ImageFilterFx";
Bitmap fxBitmap;
- public ImageFilterFx(Bitmap fxBitmap) {
- mName = "fx";
+ public ImageFilterFx(Bitmap fxBitmap,String name) {
+ setFilterType(TYPE_FX);
+ mName = name;
this.fxBitmap = fxBitmap;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
index 311ae6310..3d48b7e53 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java
@@ -18,14 +18,12 @@ package com.android.gallery3d.filtershow.filters;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.util.Log;
import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata.FLIP;
-import com.android.gallery3d.filtershow.imageshow.ImageGeometry;
public class ImageFilterGeometry extends ImageFilter {
private final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
@@ -65,99 +63,41 @@ public class ImageFilterGeometry extends ImageFilter {
native protected void nativeApplyFilterStraighten(Bitmap src, int srcWidth, int srcHeight,
Bitmap dst, int dstWidth, int dstHeight, float straightenAngle);
- @Override
- public Bitmap apply(Bitmap originalBitmap, float scaleFactor, boolean highQuality) {
- Rect cropBounds = new Rect();
- Rect originalBounds = new Rect();
- FLIP flipType = mGeometry.getFlipType();
- float rAngle = mGeometry.getRotation();
- float sAngle = mGeometry.getStraightenRotation();
- mGeometry.getCropBounds().roundOut(cropBounds);
- mGeometry.getPhotoBounds().roundOut(originalBounds);
- boolean flip = flipType != FLIP.NONE;
- boolean rotate = rAngle != 0;
- boolean crop = !cropBounds.equals(originalBounds);
- boolean straighten = sAngle != 0;
-
- int jniFlipType = 0;
- switch (flipType) {
- case BOTH:
- jniFlipType = BOTH;
- break;
- case VERTICAL:
- jniFlipType = VERTICAL;
- break;
- case HORIZONTAL:
- jniFlipType = HORIZONTAL;
- break;
- default:
- jniFlipType = 0;
- break;
- }
- int bmWidth = originalBitmap.getWidth();
- int bmHeight = originalBitmap.getHeight();
- if (!(flip || rotate || crop || straighten)) {
- return originalBitmap;
- }
- if (originalBounds.width() != bmWidth || originalBounds.height() != bmHeight) {
- if (LOGV)
- Log.v(LOGTAG, "PHOTOBOUNDS WIDTH/HEIGHT NOT SAME AS BITMAP WIDTH/HEIGHT");
- return originalBitmap;
- }
- Bitmap modBitmap = originalBitmap;
- Rect modifiedBounds = new Rect(originalBounds);
- if (flip) {
- modBitmap = originalBitmap.copy(mConfig, true);
- nativeApplyFilterFlip(originalBitmap, bmWidth, bmHeight, modBitmap,
- bmWidth, bmHeight, jniFlipType);
- }
- if (rotate) {
- // Fails for non-90 degree rotations
- Bitmap modBitmapRotate = null;
- rAngle %= 360;
- int deg = (int) (rAngle / 90);
- deg = -deg; // Make CCW positive
- if (deg < 0)
- deg += 4;
- // Now deg is in [1, 3] as required by native rotate
- if (deg == ONE_EIGHTY) {
- modBitmapRotate = Bitmap.createBitmap(bmWidth, bmHeight, mConfig);
- nativeApplyFilterRotate(modBitmap, bmWidth, bmHeight, modBitmapRotate,
- bmWidth, bmHeight, deg);
- modifiedBounds = new Rect(0, 0, bmWidth, bmHeight);
- } else if (deg == TWO_SEVENTY || deg == NINETY) {
- modBitmapRotate = Bitmap.createBitmap(bmHeight, bmWidth, mConfig);
- nativeApplyFilterRotate(modBitmap, bmWidth, bmHeight, modBitmapRotate,
- bmHeight, bmWidth, deg);
- modifiedBounds = new Rect(0, 0, bmHeight, bmWidth);
- }
- modBitmap = modBitmapRotate;
- }
- if (straighten) {
- Rect straightenBounds = new Rect();
- ImageGeometry.getUntranslatedStraightenCropBounds(new RectF(modifiedBounds), sAngle)
- .roundOut(straightenBounds);
- Bitmap modBitmapStraighten = Bitmap.createBitmap(straightenBounds.width(),
- straightenBounds.height(), mConfig);
- nativeApplyFilterStraighten(modBitmap, modifiedBounds.width(), modifiedBounds.height(),
- modBitmapStraighten,
- straightenBounds.width(), straightenBounds.height(),
- mGeometry.getStraightenRotation());
- modifiedBounds = straightenBounds;
- modBitmap = modBitmapStraighten;
+ public Matrix buildMatrix(RectF r) {
+ float dx = r.width()/2;
+ float dy = r.height()/2;
+ if(mGeometry.hasSwitchedWidthHeight()){
+ float temp = dx;
+ dx = dy;
+ dy = temp;
}
- if (crop) {
- Bitmap modBitmapCrop = Bitmap.createBitmap(cropBounds.width(), cropBounds.height(),
- mConfig);
- // Force crop bounds to be within straighten bounds.
- if (!modifiedBounds.intersect(cropBounds)) {
- return modBitmap;
- }
- nativeApplyFilterCrop(modBitmap, bmWidth, bmHeight, modBitmapCrop,
- cropBounds.width(), cropBounds.height(), cropBounds.left, cropBounds.top);
- modBitmap = modBitmapCrop;
+ float w = r.left * 2 + r.width();
+ float h = r.top * 2 + r.height();
+ Matrix m = mGeometry.buildGeometryMatrix(w, h, 1f, dx, dy, false);
+
+ return m;
+ }
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+ // 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?)
+ 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);
}
- return modBitmap;
+
+ Matrix drawMatrix = buildMatrix(crop);
+ Canvas canvas = new Canvas(temp);
+ canvas.drawBitmap(bitmap, drawMatrix, new Paint());
+ return temp;
}
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
index 2ead04764..3649d28fa 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
@@ -14,11 +14,13 @@ public class ImageFilterParametricBorder extends ImageFilter {
private int mBorderCornerRadius = 10;
public ImageFilterParametricBorder() {
+ setFilterType(TYPE_BORDER);
mName = "Border";
}
public ImageFilterParametricBorder(int color, int size, int radius) {
setBorder(color, size, radius);
+ setFilterType(TYPE_BORDER);
}
@Override
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
index 4c43410e3..fed583832 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
@@ -6,6 +6,7 @@ import android.graphics.Bitmap;
public class ImageFilterVignette extends ImageFilter {
public ImageFilterVignette() {
+ setFilterType(TYPE_VIGNETTE);
mName = "Vignette";
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
index 163ed0c65..5e613ebce 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
@@ -8,6 +8,7 @@ public class ImageFilterWBalance extends ImageFilter {
private static final String TAG = "ImageFilterWBalance";
public ImageFilterWBalance() {
+ setFilterType(TYPE_WBALANCE);
mName = "WBalance";
}
@@ -17,7 +18,6 @@ public class ImageFilterWBalance extends ImageFilter {
public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
- Log.v(TAG,"White Balance Call");
nativeApplyFilter(bitmap, w, h, -1,-1);
return bitmap;
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
index 4f172285d..352fa5bf3 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java
@@ -17,28 +17,23 @@
package com.android.gallery3d.filtershow.imageshow;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
import android.graphics.RectF;
import com.android.gallery3d.filtershow.filters.ImageFilterGeometry;
-/**
- * This class holds metadata about an image's geometry. Specifically: rotation,
- * scaling, cropping, and image boundaries. It maintains the invariant that the
- * cropping boundaries are within or equal to the image boundaries (before
- * rotation) WHEN mSafe is true.
- */
-
public class GeometryMetadata {
// Applied in order: rotate, crop, scale.
// Do not scale saved image (presumably?).
private static final ImageFilterGeometry mImageFilter = new ImageFilterGeometry();
- private float mScaleFactor = 0;
+ private float mScaleFactor = 1.0f;
private float mRotation = 0;
private float mStraightenRotation = 0;
private final RectF mCropBounds = new RectF();
private final RectF mPhotoBounds = new RectF();
private FLIP mFlip = FLIP.NONE;
- private boolean mSafe = false;
+
+ private RectF mBounds = new RectF();
public enum FLIP {
NONE, VERTICAL, HORIZONTAL, BOTH
@@ -51,31 +46,12 @@ public class GeometryMetadata {
set(g);
}
- public Bitmap apply(Bitmap original, float scaleFactor, boolean highQuality){
+ public Bitmap apply(Bitmap original, float scaleFactor, boolean highQuality) {
mImageFilter.setGeometryMetadata(this);
Bitmap m = mImageFilter.apply(original, scaleFactor, highQuality);
- mPhotoBounds.set(0,0, m.getWidth(), m.getHeight());
- mCropBounds.set(mPhotoBounds);
- mScaleFactor = 0;
- mRotation = 0;
- mStraightenRotation = 0;
- mFlip = FLIP.NONE;
- mSafe = false;
return m;
}
- public GeometryMetadata(float scale, float rotation, float straighten, RectF cropBounds,
- RectF photoBounds, FLIP flipType) {
- mScaleFactor = scale;
- mRotation = rotation;
- mStraightenRotation = straighten;
- mCropBounds.set(cropBounds);
- mPhotoBounds.set(photoBounds);
- mFlip = flipType;
- mSafe = cropFitsInPhoto(mCropBounds);
- }
-
- // Safe as long as invariant holds.
public void set(GeometryMetadata g) {
mScaleFactor = g.mScaleFactor;
mRotation = g.mRotation;
@@ -83,35 +59,7 @@ public class GeometryMetadata {
mCropBounds.set(g.mCropBounds);
mPhotoBounds.set(g.mPhotoBounds);
mFlip = g.mFlip;
- mSafe = g.mSafe;
- }
-
- public void safeSet(GeometryMetadata g) {
- if (g.safe()) {
- set(g);
- return;
- }
-
- mScaleFactor = g.mScaleFactor;
- mRotation = g.mRotation;
- mStraightenRotation = g.mStraightenRotation;
- mCropBounds.set(g.mCropBounds);
- safeSetPhotoBounds(g.mPhotoBounds);
- mFlip = g.mFlip;
- }
-
- public void safeSet(float scale,
- float rotation,
- float straighten,
- RectF cropBounds,
- RectF photoBounds,
- FLIP flipType) {
- mScaleFactor = scale;
- mStraightenRotation = straighten;
- mRotation = rotation;
- mCropBounds.set(cropBounds);
- safeSetPhotoBounds(photoBounds);
- mFlip = flipType;
+ mBounds = g.mBounds;
}
public float getScaleFactor() {
@@ -126,10 +74,19 @@ public class GeometryMetadata {
return mStraightenRotation;
}
- public RectF getCropBounds() {
+ public RectF getPreviewCropBounds() {
return new RectF(mCropBounds);
}
+ public RectF getCropBounds(Bitmap bitmap) {
+ float scale = 1.0f;
+ if (mPhotoBounds.width() > 0) {
+ scale = bitmap.getWidth() / mPhotoBounds.width();
+ }
+ return new RectF(mCropBounds.left * scale, mCropBounds.top * scale,
+ mCropBounds.right * scale, mCropBounds.bottom * scale);
+ }
+
public FLIP getFlipType() {
return mFlip;
}
@@ -138,10 +95,6 @@ public class GeometryMetadata {
return new RectF(mPhotoBounds);
}
- public boolean safe() {
- return mSafe;
- }
-
public void setScaleFactor(float scale) {
mScaleFactor = scale;
}
@@ -158,41 +111,12 @@ public class GeometryMetadata {
mStraightenRotation = straighten;
}
- /**
- * Sets crop bounds to be the intersection of mPhotoBounds and the new crop
- * bounds. If there was no intersection, returns false and does not set crop
- * bounds
- */
- public boolean safeSetCropBounds(RectF newCropBounds) {
- if (mCropBounds.setIntersect(newCropBounds, mPhotoBounds)) {
- mSafe = true;
- return true;
- }
- return false;
- }
-
public void setCropBounds(RectF newCropBounds) {
mCropBounds.set(newCropBounds);
- mSafe = false;
- }
-
- /**
- * Sets mPhotoBounds to be the new photo bounds and sets mCropBounds to be
- * the intersection of the new photo bounds and the old crop bounds. Sets
- * the crop bounds to mPhotoBounds if there is no intersection.
- */
-
- public void safeSetPhotoBounds(RectF newPhotoBounds) {
- mPhotoBounds.set(newPhotoBounds);
- if (!mCropBounds.intersect(mPhotoBounds)) {
- mCropBounds.set(mPhotoBounds);
- }
- mSafe = true;
}
public void setPhotoBounds(RectF newPhotoBounds) {
mPhotoBounds.set(newPhotoBounds);
- mSafe = false;
}
public boolean cropFitsInPhoto(RectF cropBounds) {
@@ -210,7 +134,7 @@ public class GeometryMetadata {
return (mScaleFactor == d.mScaleFactor &&
mRotation == d.mRotation &&
mStraightenRotation == d.mStraightenRotation &&
- mFlip == d.mFlip && mSafe == d.mSafe &&
+ mFlip == d.mFlip &&
mCropBounds.equals(d.mCropBounds) && mPhotoBounds.equals(d.mPhotoBounds));
}
@@ -223,17 +147,76 @@ public class GeometryMetadata {
result = 31 * result + mFlip.hashCode();
result = 31 * result + mCropBounds.hashCode();
result = 31 * result + mPhotoBounds.hashCode();
- result = 31 * result + (mSafe ? 1 : 0);
return result;
}
@Override
public String toString() {
return getClass().getName() + "[" + "scale=" + mScaleFactor
- + ",rotation=" + mRotation + ",flip=" + mFlip + ",safe="
- + (mSafe ? "true" : "false") + ",straighten="
+ + ",rotation=" + mRotation + ",flip=" + mFlip + ",straighten="
+ mStraightenRotation + ",cropRect=" + mCropBounds.toShortString()
+ ",photoRect=" + mPhotoBounds.toShortString() + "]";
}
+ protected Matrix getHorizontalMatrix(float width) {
+ Matrix flipHorizontalMatrix = new Matrix();
+ flipHorizontalMatrix.setScale(-1, 1);
+ flipHorizontalMatrix.postTranslate(width, 0);
+ return flipHorizontalMatrix;
+ }
+
+ protected Matrix getVerticalMatrix(float height) {
+ Matrix flipVerticalMatrix = new Matrix();
+ flipVerticalMatrix.setScale(1, -1);
+ flipVerticalMatrix.postTranslate(0, height);
+ return flipVerticalMatrix;
+ }
+
+ public Matrix getFlipMatrix(float width, float height) {
+ FLIP type = getFlipType();
+ 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 boolean hasSwitchedWidthHeight() {
+ return (((int) (mRotation / 90)) % 2) != 0;
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+
+ 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);
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
index 836ec82f8..4d171bf4c 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
@@ -22,17 +22,12 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.MotionEvent;
import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.presets.ImagePreset;
-
public class ImageCrop extends ImageGeometry {
private static final boolean LOGV = false;
private static final int MOVE_LEFT = 1;
@@ -43,19 +38,14 @@ public class ImageCrop extends ImageGeometry {
private static final float MIN_CROP_WIDTH_HEIGHT = 0.1f;
private static final int TOUCH_TOLERANCE = 30;
- private static final int SHADOW_ALPHA = 160;
- private float mAspectWidth = 4;
- private float mAspectHeight = 3;
- private boolean mFixAspectRatio = false; // not working yet
+ private boolean mFirstDraw = true;
+ private float mAspectWidth = 1;
+ private float mAspectHeight = 1;
+ private boolean mFixAspectRatio = false;
private final Paint borderPaint;
- private float mCropOffsetX = 0;
- private float mCropOffsetY = 0;
- private float mPrevOffsetX = 0;
- private float mPrevOffsetY = 0;
-
private int movingEdges;
private final Drawable cropIndicator;
private final int indicatorSize;
@@ -89,15 +79,15 @@ public class ImageCrop extends ImageGeometry {
}
private float getScaledMinWidthHeight() {
- RectF disp = getLocalDisplayBounds();
+ RectF disp = new RectF(0, 0, getWidth(), getHeight());
float scaled = Math.min(disp.width(), disp.height()) * MIN_CROP_WIDTH_HEIGHT
- / getLocalScale();
+ / computeScale(getWidth(), getHeight());
return scaled;
}
- protected static Matrix getCropRotationMatrix(float rotation, RectF localImage) {
- Matrix m = new Matrix();
- m.setRotate(rotation, localImage.centerX(), localImage.centerY());
+ 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;
}
@@ -117,7 +107,7 @@ public class ImageCrop extends ImageGeometry {
m.mapRect(crop);
}
m = new Matrix();
- float zoom = getLocalScale();
+ float zoom = computeScale(getWidth(), getHeight());
m.setScale(zoom, zoom, mCenterX, mCenterY);
m.preTranslate(mXOffset, mYOffset);
m.mapRect(crop);
@@ -139,6 +129,44 @@ public class ImageCrop extends ImageGeometry {
return crop;
}
+ 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 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;
+ }
+
/**
* Sets cropped bounds; modifies the bounds if it's smaller than the allowed
* dimensions.
@@ -147,16 +175,33 @@ public class ImageCrop extends ImageGeometry {
// Avoid cropping smaller than minimum width or height.
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;
+ }
+ }
float newWidth = cbounds.width();
float newHeight = cbounds.height();
- if (newWidth < minWidthHeight) {
- newWidth = minWidthHeight;
- }
- if (newHeight < minWidthHeight) {
- newHeight = minWidthHeight;
+ 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;
+ }
}
-
RectF pbounds = getLocalPhotoBounds();
if (pbounds.width() < minWidthHeight) {
newWidth = pbounds.width();
@@ -166,13 +211,14 @@ public class ImageCrop extends ImageGeometry {
}
cbounds.set(cbounds.left, cbounds.top, cbounds.left + newWidth, cbounds.top + newHeight);
- RectF snappedCrop = findCropBoundForRotatedImg(cbounds, pbounds, getLocalStraighten(),
- mCenterX - mXOffset, mCenterY - mYOffset);
+ RectF straightenBounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
+ getLocalStraighten());
+ cbounds.intersect(straightenBounds);
+
if (mFixAspectRatio) {
- // TODO: add aspect ratio stuff
- fixAspectRatio(snappedCrop, mAspectWidth, mAspectHeight);
+ fixAspectRatio(cbounds, aw, ah);
}
- setLocalCropBounds(snappedCrop);
+ setLocalCropBounds(cbounds);
invalidate();
}
@@ -199,33 +245,88 @@ public class ImageCrop extends ImageGeometry {
else if (bottom <= TOUCH_TOLERANCE) {
movingEdges |= MOVE_BOTTOM;
}
+ // Check inside block.
+ if (cropped.contains(x, y) && (movingEdges == 0)) {
+ movingEdges = MOVE_BLOCK;
+ }
invalidate();
}
private void moveEdges(float dX, float dY) {
RectF cropped = getRotatedCropBounds();
float minWidthHeight = getScaledMinWidthHeight();
- float scale = getLocalScale();
+ float scale = computeScale(getWidth(), getHeight());
float deltaX = dX / scale;
float deltaY = dY / scale;
- if (movingEdges == MOVE_BLOCK) {
- // TODO
+ int select = movingEdges;
+ if (mFixAspectRatio && (select != MOVE_BLOCK)) {
+ if ((select & MOVE_LEFT) != 0) {
+ select &= ~MOVE_BOTTOM;
+ select |= MOVE_TOP;
+ deltaY = getNewHeightForWidthAspect(deltaX, mAspectWidth, mAspectHeight);
+ }
+ if ((select & MOVE_TOP) != 0) {
+ select &= ~MOVE_RIGHT;
+ select |= MOVE_LEFT;
+ deltaX = getNewWidthForHeightAspect(deltaY, mAspectWidth, mAspectHeight);
+ }
+ if ((select & MOVE_RIGHT) != 0) {
+ select &= ~MOVE_TOP;
+ select |= MOVE_BOTTOM;
+ deltaY = getNewHeightForWidthAspect(deltaX, mAspectWidth, mAspectHeight);
+ }
+ if ((select & MOVE_BOTTOM) != 0) {
+ select &= ~MOVE_LEFT;
+ select |= MOVE_RIGHT;
+ deltaX = getNewWidthForHeightAspect(deltaY, mAspectWidth, mAspectHeight);
+ }
+ }
+
+ 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);
} else {
- if ((movingEdges & MOVE_LEFT) != 0) {
- cropped.left = Math.min(cropped.left + deltaX, cropped.right - minWidthHeight);
- fixRectAspectW(cropped);
+ float dx = 0;
+ float dy = 0;
+ if ((select & MOVE_LEFT) != 0) {
+ dx = Math.min(cropped.left + deltaX, cropped.right - minWidthHeight) - cropped.left;
+ }
+ if ((select & MOVE_TOP) != 0) {
+ dy = Math.min(cropped.top + deltaY, cropped.bottom - minWidthHeight) - cropped.top;
+ }
+ if ((select & MOVE_RIGHT) != 0) {
+ dx = Math.max(cropped.right + deltaX, cropped.left + minWidthHeight)
+ - cropped.right;
+ }
+ if ((select & MOVE_BOTTOM) != 0) {
+ dy = Math.max(cropped.bottom + deltaY, cropped.top + minWidthHeight)
+ - cropped.bottom;
+ }
+
+ if (mFixAspectRatio) {
+ if (dx < dy) {
+ dy = getNewHeightForWidthAspect(dx, mAspectWidth, mAspectHeight);
+ } else {
+ dx = getNewWidthForHeightAspect(dy, mAspectWidth, mAspectHeight);
+ }
+ }
+
+ if ((select & MOVE_LEFT) != 0) {
+ cropped.left += dx;
}
- if ((movingEdges & MOVE_TOP) != 0) {
- cropped.top = Math.min(cropped.top + deltaY, cropped.bottom - minWidthHeight);
- fixRectAspectH(cropped);
+ if ((select & MOVE_TOP) != 0) {
+ cropped.top += dy;
}
- if ((movingEdges & MOVE_RIGHT) != 0) {
- cropped.right = Math.max(cropped.right + deltaX, cropped.left + minWidthHeight);
- fixRectAspectW(cropped);
+ if ((select & MOVE_RIGHT) != 0) {
+ cropped.right += dx;
}
- if ((movingEdges & MOVE_BOTTOM) != 0) {
- cropped.bottom = Math.max(cropped.bottom + deltaY, cropped.top + minWidthHeight);
- fixRectAspectH(cropped);
+ if ((select & MOVE_BOTTOM) != 0) {
+ cropped.bottom += dy;
}
}
Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds());
@@ -241,31 +342,6 @@ public class ImageCrop extends ImageGeometry {
setCropBounds(cropped);
}
- private void fixRectAspectH(RectF cropped) {
- if (mFixAspectRatio) {
- float half = getNewWidthForHeightAspect(cropped.height(), mAspectWidth, mAspectHeight) / 2;
- float mid = (cropped.right - cropped.left) / 2;
- cropped.left = mid - half;
- cropped.right = mid + half;
- }
- }
-
- private void fixRectAspectW(RectF cropped) {
- if (mFixAspectRatio) {
- float half = getNewHeightForWidthAspect(cropped.width(), mAspectWidth, mAspectHeight) / 2;
- float mid = (cropped.bottom - cropped.top) / 2;
- cropped.top = mid - half;
- cropped.bottom = mid + half;
- }
- }
-
- private void drawShadow(Canvas canvas, float left, float top, float right, float bottom) {
- canvas.save();
- canvas.clipRect(left, top, right, bottom);
- canvas.drawARGB(SHADOW_ALPHA, 0, 0, 0);
- canvas.restore();
- }
-
private void drawIndicator(Canvas canvas, Drawable indicator, float centerX, float centerY) {
int left = (int) centerX - indicatorSize / 2;
int top = (int) centerY - indicatorSize / 2;
@@ -277,28 +353,43 @@ public class ImageCrop extends ImageGeometry {
protected void setActionDown(float x, float y) {
super.setActionDown(x, y);
detectMovingEdges(x, y);
- if (movingEdges == 0) {
- mPrevOffsetX = mCropOffsetX;
- mPrevOffsetY = mCropOffsetY;
- }
+ }
+
+ @Override
+ protected void setActionUp() {
+ super.setActionUp();
+ movingEdges = 0;
}
@Override
protected void setActionMove(float x, float y) {
- if (movingEdges != 0) {
+ if (movingEdges != 0)
moveEdges(x - mCurrentX, y - mCurrentY);
+
+ super.setActionMove(x, y);
+ }
+
+ private void cropSetup() {
+ if (mFixAspectRatio) {
+ RectF cb = getRotatedCropBounds();
+ fixAspectRatio(cb, mAspectWidth, mAspectHeight);
+ RectF cb0 = getUnrotatedCropBounds(cb);
+ setCropBounds(cb0);
} else {
- float dx = x - mTouchCenterX;
- float dy = y - mTouchCenterY;
- mCropOffsetX = dx + mPrevOffsetX;
- mCropOffsetY = dy + mPrevOffsetY;
+ setCropBounds(getLocalCropBounds());
}
- super.setActionMove(x, y);
}
@Override
protected void gainedVisibility() {
- setCropBounds(getLocalCropBounds());
+ cropSetup();
+ mFirstDraw = true;
+ }
+
+ @Override
+ public void resetParameter() {
+ super.resetParameter();
+ cropSetup();
}
@Override
@@ -307,48 +398,66 @@ 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);
- drawRegularFlippedBitmap(canvas, image, gPaint);
-
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
- RectF boundsRect = getCropBoundsDisplayed();
- gPaint.setARGB(128, 0, 0, 0);
- gPaint.setStyle(Paint.Style.FILL);
- // TODO: move this to style when refactoring
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
-
- Path path = new Path();
- path.addRect(boundsRect, Path.Direction.CCW);
- gPaint.setARGB(255, 255, 255, 255);
+ if (mFirstDraw) {
+ cropSetup();
+ mFirstDraw = false;
+ }
+ float rotation = getLocalRotation();
+ drawTransformedBitmap(canvas, image, gPaint, true);
+
+ gPaint.setARGB(255, 125, 255, 128);
gPaint.setStrokeWidth(3);
gPaint.setStyle(Paint.Style.STROKE);
-
- canvas.drawPath(path, gPaint);
-
- boolean notMoving = movingEdges == 0;
- if (((movingEdges & MOVE_TOP) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.centerX(), boundsRect.top);
+ drawStraighten(canvas, gPaint);
+ RectF scaledCrop = unrotatedCropBounds();
+ int decoded_moving = decoder(movingEdges, rotation);
+ canvas.save();
+ canvas.rotate(rotation, mCenterX, mCenterY);
+ boolean notMoving = decoded_moving == 0;
+ if (((decoded_moving & MOVE_TOP) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top);
}
- if (((movingEdges & MOVE_BOTTOM) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.centerX(), boundsRect.bottom);
+ if (((decoded_moving & MOVE_BOTTOM) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.bottom);
}
- if (((movingEdges & MOVE_LEFT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.left, boundsRect.centerY());
+ if (((decoded_moving & MOVE_LEFT) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.centerY());
}
- if (((movingEdges & MOVE_RIGHT) != 0) || notMoving) {
- drawIndicator(canvas, cropIndicator, boundsRect.right, boundsRect.centerY());
+ if (((decoded_moving & MOVE_RIGHT) != 0) || notMoving) {
+ drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.centerY());
}
+ 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;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java b/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
index ba01d888a..3408405dc 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageFlip.java
@@ -19,9 +19,7 @@ package com.android.gallery3d.filtershow.imageshow;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
@@ -125,55 +123,7 @@ public class ImageFlip extends ImageGeometry {
gPaint.setFilterBitmap(true);
gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
-
- FLIP flip = mNextFlip;
- canvas.save();
- float zoom = getLocalScale();
- canvas.rotate(getTotalLocalRotation(), mCenterX, mCenterY);
- canvas.scale(zoom, zoom, mCenterX, mCenterY);
- canvas.translate(mXOffset, mYOffset);
- if (flip == FLIP.HORIZONTAL) {
- Matrix flipper = getHorizontalMatrix(image.getWidth());
- canvas.drawBitmap(image, flipper, gPaint);
- } else if (flip == FLIP.VERTICAL) {
- Matrix flipper = getVerticalMatrix(image.getHeight());
- canvas.drawBitmap(image, flipper, gPaint);
- } else if (flip == FLIP.BOTH) {
- Matrix flipper = getVerticalMatrix(image.getHeight());
- flipper.postConcat(getHorizontalMatrix(image.getWidth()));
- canvas.drawBitmap(image, flipper, gPaint);
- } else {
- canvas.drawBitmap(image, 0, 0, gPaint);
- }
- canvas.restore();
-
- RectF cropBounds = getCropBoundsDisplayed(getLocalCropBounds());
-
- Matrix m0 = new Matrix();
- m0.setRotate(getLocalRotation(), mCenterX, mCenterY);
- float[] corners = getCornersFromRect(cropBounds);
- m0.mapPoints(corners);
- gPaint.setARGB(255, 255, 255, 255);
- // TODO: pull out style to xml
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
- drawClosedPath(canvas, gPaint, corners);
-
- canvas.save();
- canvas.rotate(getLocalRotation(), mCenterX, mCenterY);
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
- RectF boundsRect = cropBounds;
- gPaint.setARGB(128, 0, 0, 0);
- gPaint.setStyle(Paint.Style.FILL);
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
- canvas.rotate(-getLocalRotation(), mCenterX, mCenterY);
- canvas.restore();
+ drawTransformedBitmap(canvas, image, gPaint, false);
}
+
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java b/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
index 606e4770c..68df702ea 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
@@ -19,12 +19,13 @@ package com.android.gallery3d.filtershow.imageshow;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -47,7 +48,7 @@ public abstract class ImageGeometry extends ImageSlave {
protected float mTouchCenterY;
// Local geometry data
- private GeometryMetadata mLocalGeoMetadata = null;
+ private GeometryMetadata mLocalGeometry = null;
private RectF mLocalDisplayBounds = null;
protected float mXOffset = 0;
protected float mYOffset = 0;
@@ -73,10 +74,20 @@ public abstract class ImageGeometry extends ImageSlave {
calculateLocalScalingFactorAndOffset();
}
+ protected float computeScale(float width, float height) {
+ float imageWidth = mLocalGeometry.getPhotoBounds().width();
+ float imageHeight = mLocalGeometry.getPhotoBounds().height();
+ float zoom = width / imageWidth;
+ if (imageHeight > imageWidth) {
+ zoom = height / imageHeight;
+ }
+ return zoom;
+ }
+
private void calculateLocalScalingFactorAndOffset() {
- if (mLocalGeoMetadata == null || mLocalDisplayBounds == null)
+ if (mLocalGeometry == null || mLocalDisplayBounds == null)
return;
- RectF imageBounds = mLocalGeoMetadata.getPhotoBounds();
+ RectF imageBounds = mLocalGeometry.getPhotoBounds();
float imageWidth = imageBounds.width();
float imageHeight = imageBounds.height();
float displayWidth = mLocalDisplayBounds.width();
@@ -84,13 +95,9 @@ public abstract class ImageGeometry extends ImageSlave {
mCenterX = displayWidth / 2;
mCenterY = displayHeight / 2;
- float zoom = displayWidth / imageWidth;
- if (imageHeight > imageWidth) {
- zoom = displayHeight / imageHeight;
- }
mYOffset = (displayHeight - imageHeight) / 2.0f;
mXOffset = (displayWidth - imageWidth) / 2.0f;
- mLocalGeoMetadata.setScaleFactor(zoom);
+ updateScale();
}
@Override
@@ -104,22 +111,18 @@ public abstract class ImageGeometry extends ImageSlave {
invalidate();
}
- private GeometryMetadata getMasterImageGeometryMetadataCopy() {
- return getMaster().getGeometry();
- }
-
// Overwrites local with master
protected void syncLocalToMasterGeometry() {
- mLocalGeoMetadata = getMasterImageGeometryMetadataCopy();
+ mLocalGeometry = getMaster().getGeometry();
calculateLocalScalingFactorAndOffset();
}
protected RectF getLocalPhotoBounds() {
- return mLocalGeoMetadata.getPhotoBounds();
+ return mLocalGeometry.getPhotoBounds();
}
protected RectF getLocalCropBounds() {
- return mLocalGeoMetadata.getCropBounds();
+ return mLocalGeometry.getPreviewCropBounds();
}
protected RectF getLocalDisplayBounds() {
@@ -127,39 +130,62 @@ public abstract class ImageGeometry extends ImageSlave {
}
protected float getLocalScale() {
- return mLocalGeoMetadata.getScaleFactor();
+ return mLocalGeometry.getScaleFactor();
}
protected float getLocalRotation() {
- return mLocalGeoMetadata.getRotation();
+ return mLocalGeometry.getRotation();
}
protected float getLocalStraighten() {
- return mLocalGeoMetadata.getStraightenRotation();
+ return mLocalGeometry.getStraightenRotation();
}
protected void setLocalScale(float s) {
- mLocalGeoMetadata.setScaleFactor(s);
+ mLocalGeometry.setScaleFactor(s);
+ }
+
+ protected void updateScale() {
+ RectF bounds = getUntranslatedStraightenCropBounds(mLocalGeometry.getPhotoBounds(),
+ getLocalStraighten());
+ float zoom = computeScale(bounds.width(), bounds.height());
+ setLocalScale(zoom);
}
protected void setLocalRotation(float r) {
- mLocalGeoMetadata.setRotation(r);
+ mLocalGeometry.setRotation(r);
+ updateScale();
+ }
+
+ /**
+ * Constrains rotation to be in [0, 90, 180, 270].
+ */
+ protected int constrainedRotation(float rotation) {
+ int r = (int) ((rotation % 360) / 90);
+ r = (r < 0) ? (r + 4) : r;
+ return r * 90;
+ }
+
+ protected Matrix getLocalGeoFlipMatrix(float width, float height) {
+ return mLocalGeometry.getFlipMatrix(width, height);
}
protected void setLocalStraighten(float r) {
- mLocalGeoMetadata.setStraightenRotation(r);
+ mLocalGeometry.setStraightenRotation(r);
+ updateScale();
}
protected void setLocalCropBounds(RectF c) {
- mLocalGeoMetadata.setCropBounds(c);
+ mLocalGeometry.setCropBounds(c);
+ updateScale();
}
protected FLIP getLocalFlip() {
- return mLocalGeoMetadata.getFlipType();
+ return mLocalGeometry.getFlipType();
}
protected void setLocalFlip(FLIP flip) {
- mLocalGeoMetadata.setFlipType(flip);
+ mLocalGeometry.setFlipType(flip);
}
protected float getTotalLocalRotation() {
@@ -172,74 +198,21 @@ public abstract class ImageGeometry extends ImageSlave {
return getMaster().mForegroundImage;
}
- protected static Matrix getHorizontalMatrix(int width) {
- Matrix flipHorizontalMatrix = new Matrix();
- flipHorizontalMatrix.setScale(-1, 1);
- flipHorizontalMatrix.postTranslate(width, 0);
- return flipHorizontalMatrix;
- }
-
- protected static Matrix getVerticalMatrix(int height) {
- Matrix flipVerticalMatrix = new Matrix();
- flipVerticalMatrix.setScale(1, -1);
- flipVerticalMatrix.postTranslate(0, height);
- return flipVerticalMatrix;
- }
-
- protected static Matrix getFlipMatrix(FLIP type, int width, int height) {
- 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;
- }
- }
-
- protected static float clamp(float i, float low, float high) {
- return Math.max(Math.min(i, high), low);
- }
-
protected static float[] getCornersFromRect(RectF r) {
// Order is:
// 0------->1
- // ^ |
- // | v
+ // ^ |
+ // | 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
+ r.left, r.bottom // 3
+ };
return corners;
}
- // Returns maximal rectangular crop bound that still fits within
- // the image bound after the image has been rotated.
- protected static RectF findCropBoundForRotatedImg(RectF cropBound,
- RectF imageBound,
- float rotation,
- float centerX,
- float centerY) {
- Matrix m = new Matrix();
- float[] cropEdges = getCornersFromRect(cropBound);
- m.setRotate(rotation, centerX, centerY);
- Matrix m0 = new Matrix();
- if (!m.invert(m0))
- return null;
- m0.mapPoints(cropEdges);
- getEdgePoints(imageBound, cropEdges);
- m.mapPoints(cropEdges);
- return trapToRect(cropEdges);
- }
-
// 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) {
@@ -251,24 +224,6 @@ public abstract class ImageGeometry extends ImageSlave {
}
}
- protected static RectF trapToRect(float[] array) {
- float dx0 = array[4] - array[0];
- float dy0 = array[5] - array[1];
- float dx1 = array[6] - array[2];
- float dy1 = array[7] - array[3];
- float l0 = dx0 * dx0 + dy0 * dy0;
- float l1 = dx1 * dx1 + dy1 * dy1;
- if (l0 > l1) {
- RectF n = new RectF(array[2], array[3], array[6], array[7]);
- n.sort();
- return n;
- } else {
- RectF n = new RectF(array[0], array[1], array[4], array[5]);
- n.sort();
- return n;
- }
- }
-
protected static Path drawClosedPath(Canvas canvas, Paint paint, float[] points) {
Path crop = new Path();
crop.moveTo(points[0], points[1]);
@@ -280,26 +235,14 @@ public abstract class ImageGeometry extends ImageSlave {
return crop;
}
- 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];
- float xdelt = x2 - x1;
- float ydelt = y2 - y1;
- if (xdelt == 0 && ydelt == 0)
- return null;
- float u = ((point[0] - x1) * xdelt + (point[1] - y1) * ydelt)
- / (xdelt * xdelt + ydelt * ydelt);
- float[] ret = {
- (x1 + u * (x2 - x1)), (y1 + u * (y2 - y1))
- };
- return ret;
- }
-
protected static void fixAspectRatio(RectF r, float w, float h) {
float scale = Math.min(r.width() / w, r.height() / h);
- r.set(r.left, r.top, scale * w, scale * 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) {
@@ -316,6 +259,7 @@ public abstract class ImageGeometry extends ImageSlave {
if (visibility == View.VISIBLE) {
mVisibilityGained = true;
syncLocalToMasterGeometry();
+ updateScale();
gainedVisibility();
} else {
if (mVisibilityGained == true && mHasDrawn == true) {
@@ -357,7 +301,7 @@ public abstract class ImageGeometry extends ImageSlave {
setNoAction();
}
if (getPanelController() != null) {
- getPanelController().onNewValue((int) getLocalValue());
+ getPanelController().onNewValue(getLocalValue());
}
invalidate();
return true;
@@ -396,116 +340,14 @@ public abstract class ImageGeometry extends ImageSlave {
protected void saveAndSetPreset() {
ImagePreset copy = new ImagePreset(getImagePreset());
- copy.setGeometry(mLocalGeoMetadata);
+ copy.setGeometry(mLocalGeometry);
+ copy.setHistoryName("Geometry");
+ copy.setIsFx(false);
setImagePreset(copy);
}
- @Override
- public void updateImage() {
- }
-
- protected void drawRegularFlippedBitmap(Canvas canvas, Bitmap image, Paint p) {
- float zoom = getLocalScale();
- canvas.save();
- canvas.rotate(getTotalLocalRotation(), mCenterX, mCenterY);
- canvas.scale(zoom, zoom, mCenterX, mCenterY);
- canvas.translate(mXOffset, mYOffset);
- Matrix flipper = getFlipMatrix(getLocalFlip(), image.getWidth(), image.getHeight());
- canvas.drawBitmap(image, flipper, p);
- canvas.restore();
- }
-
- protected void drawRegularBitmap(Canvas canvas, Bitmap image, Paint p) {
- float zoom = getLocalScale();
- canvas.save();
- canvas.rotate(getTotalLocalRotation(), mCenterX, mCenterY);
- canvas.scale(zoom, zoom, mCenterX, mCenterY);
- canvas.translate(mXOffset, mYOffset);
- canvas.drawBitmap(image, 0, 0, p);
- canvas.restore();
- }
-
- protected RectF getCropBoundsDisplayed() {
- return getCropBoundsDisplayed(getLocalCropBounds());
- }
-
- protected RectF getCropBoundsDisplayed(RectF bounds) {
- RectF crop = new RectF(bounds);
- Matrix m = new Matrix();
- float zoom = getLocalScale();
- m.setScale(zoom, zoom, mCenterX, mCenterY);
- m.preTranslate(mXOffset, mYOffset);
- m.mapRect(crop);
- return crop;
- }
-
- protected static float[] correctAngles(float rotation, float straighten) {
- float[] ret = {
- rotation, straighten
- };
- if (straighten >= MIN_STRAIGHTEN_ANGLE && straighten <= MAX_STRAIGHTEN_ANGLE
- && (rotation % 90 == 0)) {
- return ret;
- }
- float remainder = rotation % 90;
- float newRot = (int) (rotation / 90);
- float tempStraighten = straighten + remainder;
- newRot += (int) (tempStraighten / 90);
- tempStraighten %= 90;
- if (tempStraighten > MAX_STRAIGHTEN_ANGLE) {
- tempStraighten -= 90;
- newRot += 1;
- } else if (tempStraighten < MIN_STRAIGHTEN_ANGLE) {
- tempStraighten += 90;
- newRot -= 1;
- }
- ret[0] = newRot * 90;
- ret[1] = tempStraighten;
- return ret;
- }
-
- protected void correctStraightenRotateAngles() {
- float straighten = getLocalStraighten();
- float rotation = getLocalRotation();
- float[] angles = correctAngles(rotation, straighten);
- setLocalStraighten(angles[1]);
- setLocalRotation(angles[0]);
- }
-
- protected static Matrix getCropRotationMatrix(float rotation) {
- Matrix m = new Matrix();
- m.setRotate(rotation);
- if (!m.rectStaysRect()) {
- return null;
- }
- return m;
- }
-
- protected RectF getStraightenCropBounds() {
- RectF imageRect = getLocalPhotoBounds();
- Matrix m = new Matrix();
- float lRot = getLocalRotation();
- m.setRotate(lRot);
- if (!m.rectStaysRect()) {
- correctStraightenRotateAngles();
- m.setRotate(getLocalRotation());
- }
- RectF crop = getStraightenCropBounds(imageRect, getLocalStraighten());
- setLocalCropBounds(crop);
- if (!m.mapRect(crop)) {
- return null;
- }
- return crop;
- }
-
- protected RectF getStraightenCropBounds(RectF imageRect, float straightenAngle) {
- RectF boundsRect = getUntranslatedStraightenCropBounds(imageRect, straightenAngle);
- RectF nonRotateImage = getLocalPhotoBounds();
- Matrix m1 = new Matrix();
- m1.setTranslate(nonRotateImage.centerX() - boundsRect.centerX(), nonRotateImage.centerY()
- - boundsRect.centerY());
- m1.mapRect(boundsRect);
- return boundsRect;
+ protected static float clamp(float i, float low, float high) {
+ return Math.max(Math.min(i, high), low);
}
public static RectF getUntranslatedStraightenCropBounds(RectF imageRect, float straightenAngle) {
@@ -532,15 +374,123 @@ public abstract class ImageGeometry extends ImageSlave {
return new RectF(left, top, right, bottom);
}
- protected void drawShadows(Canvas canvas, RectF innerBounds, RectF outerBounds, Paint p) {
- float dWidth = outerBounds.width();
- float dHeight = outerBounds.height();
- canvas.drawRect(0, 0, dWidth, innerBounds.top, p);
- canvas.drawRect(0, innerBounds.bottom, dWidth, dHeight, p);
- canvas.drawRect(0, innerBounds.top, innerBounds.left, innerBounds.bottom,
+ protected Matrix getGeoMatrix(RectF r, boolean onlyRotate) {
+ float scale = computeScale(getWidth(), getHeight());
+ 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);
+ 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.setARGB(128, 0, 0, 0);
+ 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,
+ float rotation, float centerX, float centerY) {
+ canvas.save();
+ canvas.rotate(rotation, centerX, centerY);
+
+ float x = (outerBounds.left - outerBounds.right);
+ float y = (outerBounds.top - outerBounds.bottom);
+ float longest = (float) Math.sqrt(x * x + y * y) / 2;
+ float minX = centerX - longest;
+ float maxX = centerX + longest;
+ float minY = centerY - longest;
+ float maxY = centerY + longest;
+ canvas.drawRect(minX, minY, innerBounds.right, innerBounds.top, p);
+ canvas.drawRect(minX, innerBounds.top, innerBounds.left, maxY, p);
+ canvas.drawRect(innerBounds.left, innerBounds.bottom, maxX, maxY,
p);
- canvas.drawRect(innerBounds.right, innerBounds.top, dWidth,
+ canvas.drawRect(innerBounds.right, minY, maxX,
innerBounds.bottom, p);
+ canvas.rotate(-rotation, centerX, centerY);
+ canvas.restore();
}
@Override
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java b/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
index c0999e3d0..089e11732 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageRotate.java
@@ -19,12 +19,8 @@ package com.android.gallery3d.filtershow.imageshow;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
import android.util.AttributeSet;
-import android.util.Log;
public class ImageRotate extends ImageGeometry {
private static final float MATH_PI = (float) Math.PI;
@@ -32,8 +28,7 @@ public class ImageRotate extends ImageGeometry {
private float mBaseAngle = 0;
private float mAngle = 0;
- private RectF mLocalBoundsCopy = null;
- private boolean mSnapToNinety = true;
+ private final boolean mSnapToNinety = true;
private static final String LOGTAG = "ImageRotate";
public ImageRotate(Context context, AttributeSet attrs) {
@@ -98,21 +93,6 @@ public class ImageRotate extends ImageGeometry {
}
@Override
- public void resetParameter() {
- super.resetParameter();
- mLocalBoundsCopy = getLocalCropBounds();
- }
-
- @Override
- protected void gainedVisibility() {
- mLocalBoundsCopy = getLocalCropBounds();
- }
-
- @Override
- protected void lostVisibility() {
- }
-
- @Override
protected int getLocalValue() {
return (int) getLocalRotation();
}
@@ -123,39 +103,6 @@ public class ImageRotate extends ImageGeometry {
gPaint.setFilterBitmap(true);
gPaint.setDither(true);
gPaint.setARGB(255, 255, 255, 255);
-
- drawRegularFlippedBitmap(canvas, image, gPaint);
-
- RectF cropBounds = getCropBoundsDisplayed(mLocalBoundsCopy);
-
- Matrix m0 = new Matrix();
- m0.setRotate(getLocalRotation(), mCenterX, mCenterY);
- float[] corners = getCornersFromRect(cropBounds);
- m0.mapPoints(corners);
-
- gPaint.setARGB(255, 255, 255, 255);
- gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
- drawClosedPath(canvas, gPaint, corners);
-
- canvas.save();
- canvas.rotate(getLocalRotation(), mCenterX, mCenterY);
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
- RectF boundsRect = cropBounds;
- gPaint.setARGB(128, 0, 0, 0);
- // TODO: move style to xml
- gPaint.setStyle(Paint.Style.FILL);
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
- canvas.rotate(-getLocalRotation(), mCenterX, mCenterY);
- canvas.restore();
-
+ drawTransformedBitmap(canvas, image, gPaint, true);
}
-
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index aba731293..3fd6d4f85 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -57,6 +57,7 @@ public class ImageShow extends View implements SliderListener, OnSeekBarChangeLi
private boolean mDirtyGeometry = true;
private Bitmap mBackgroundImage = null;
+ // TODO: remove protected here, it should be private
protected Bitmap mForegroundImage = null;
protected Bitmap mFilteredImage = null;
@@ -87,6 +88,14 @@ public class ImageShow extends View implements SliderListener, OnSeekBarChangeLi
private SeekBar mSeekBar = null;
private PanelController mController = null;
+ public static void setTextSize(int value) {
+ mTextSize = value;
+ }
+
+ public static void setTextPadding(int value) {
+ mTextPadding = value;
+ }
+
private final Handler mHandler = new Handler();
public void select() {
@@ -232,7 +241,7 @@ public class ImageShow extends View implements SliderListener, OnSeekBarChangeLi
return mImagePreset;
}
- public Bitmap getOriginalFrontBitmap() {
+ protected Bitmap getOriginalFrontBitmap() {
if (mImageLoader != null) {
return mImageLoader.getOriginalBitmapLarge();
}
@@ -277,7 +286,7 @@ public class ImageShow extends View implements SliderListener, OnSeekBarChangeLi
canvas.drawRect(textRect, mPaint);
mPaint.setARGB(255, 200, 200, 200);
canvas.drawText(getImagePreset().name(), mTextPadding,
- 10 + mTextPadding, mPaint);
+ 1.5f * mTextPadding, mPaint);
}
if (showControls()) {
@@ -393,7 +402,7 @@ public class ImageShow extends View implements SliderListener, OnSeekBarChangeLi
}
}
- protected void setDirtyGeometryFlag() {
+ private void setDirtyGeometryFlag() {
mDirtyGeometry = true;
}
@@ -410,6 +419,11 @@ public class ImageShow extends View implements SliderListener, OnSeekBarChangeLi
return;
float w = image.getWidth();
float h = image.getHeight();
+ GeometryMetadata geo = getImagePreset().mGeoData;
+ RectF pb = geo.getPhotoBounds();
+ if (w == pb.width() && h == pb.height()) {
+ return;
+ }
RectF r = new RectF(0, 0, w, h);
getImagePreset().mGeoData.setPhotoBounds(r);
getImagePreset().mGeoData.setCropBounds(r);
@@ -419,6 +433,7 @@ public class ImageShow extends View implements SliderListener, OnSeekBarChangeLi
public void updateImage() {
mForegroundImage = getOriginalFrontBitmap();
imageSizeChanged(mForegroundImage); // TODO: should change to filtered
+ setDirtyGeometryFlag();
}
public void updateFilteredImage(Bitmap bitmap) {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageSmallBorder.java b/src/com/android/gallery3d/filtershow/imageshow/ImageSmallBorder.java
index d0c67f783..90986f912 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageSmallBorder.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageSmallBorder.java
@@ -18,7 +18,7 @@ public class ImageSmallBorder extends ImageSmallFilter {
protected final int mSelectedBackgroundColor = Color.WHITE;
protected final int mInnerBorderColor = Color.BLACK;
protected final int mInnerBorderWidth = 2;
- protected final float mImageScaleFactor = 2.5f;
+ protected final float mImageScaleFactor = 3.5f;
public ImageSmallBorder(Context context) {
super(context);
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java b/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java
index 0b0c2c475..a5d99a098 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageSmallFilter.java
@@ -27,12 +27,20 @@ public class ImageSmallFilter extends ImageShow implements View.OnClickListener
private ImageSmallFilter mPreviousImageSmallFilter = null;
// TODO: move this to xml.
- protected final int mMargin = 12;
- protected final int mTextMargin = 8;
+ protected static int mMargin = 12;
+ protected static int mTextMargin = 8;
protected final int mBackgroundColor = Color.argb(255, 30, 32, 40);
protected final int mSelectedBackgroundColor = Color.WHITE;
protected final int mTextColor = Color.WHITE;
+ public static void setMargin(int value) {
+ mMargin = value;
+ }
+
+ public static void setTextMargin(int value) {
+ mTextMargin = value;
+ }
+
public ImageSmallFilter(Context context, AttributeSet attrs) {
super(context, attrs);
setOnClickListener(this);
@@ -46,6 +54,7 @@ public class ImageSmallFilter extends ImageShow implements View.OnClickListener
public void setImageFilter(ImageFilter filter) {
mImageFilter = filter;
mImagePreset = new ImagePreset();
+ mImagePreset.setName(filter.getName());
mImagePreset.add(mImageFilter);
}
@@ -99,7 +108,14 @@ public class ImageSmallFilter extends ImageShow implements View.OnClickListener
}
@Override
- public Bitmap getOriginalFrontBitmap() {
+ public void updateImage() {
+ // We don't want to warn listeners here that the image size has changed, because
+ // we'll be working with the small image...
+ mForegroundImage = getOriginalFrontBitmap();
+ }
+
+ @Override
+ protected Bitmap getOriginalFrontBitmap() {
if (mImageLoader == null) {
return null;
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
index 2b15bf373..2fd6b9b35 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java
@@ -19,14 +19,12 @@ package com.android.gallery3d.filtershow.imageshow;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
-import android.view.MotionEvent;
-import com.android.gallery3d.filtershow.presets.ImagePreset;
+import com.android.gallery3d.filtershow.imageshow.ImageGeometry.MODES;
public class ImageStraighten extends ImageGeometry {
@@ -50,11 +48,17 @@ public class ImageStraighten extends ImageGeometry {
mBaseAngle = mAngle = getLocalStraighten();
}
+ private void setCropToStraighten(){
+ setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
+ getLocalStraighten()));
+ }
+
@Override
protected void setActionMove(float x, float y) {
super.setActionMove(x, y);
computeValue();
setLocalStraighten(mAngle);
+ setCropToStraighten();
}
private float angleFor(float dx, float dy) {
@@ -79,13 +83,19 @@ public class ImageStraighten extends ImageGeometry {
}
@Override
- protected void gainedVisibility() {
- correctStraightenRotateAngles();
+ protected void lostVisibility() {
+ saveAndSetPreset();
}
@Override
- protected void lostVisibility() {
- saveAndSetPreset();
+ protected void gainedVisibility(){
+ setCropToStraighten();
+ }
+
+ @Override
+ protected void setActionUp() {
+ super.setActionUp();
+ setCropToStraighten();
}
@Override
@@ -104,53 +114,24 @@ public class ImageStraighten 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);
+ drawTransformedBitmap(canvas, image, gPaint, false);
- // Draw fully rotated image.
- drawRegularFlippedBitmap(canvas, image, gPaint);
-
- // Get cropping frame
- RectF boundsRect = getStraightenCropBounds();
-
- Matrix m1 = new Matrix();
- float zoom = getLocalScale();
- // Center and scale
- m1.setScale(zoom, zoom, mCenterX, mCenterY);
- m1.preTranslate(mCenterX - boundsRect.centerX(), mCenterY - boundsRect.centerY());
- m1.mapRect(boundsRect);
- RectF displayRect = getLocalDisplayBounds();
- float dWidth = displayRect.width();
- float dHeight = displayRect.height();
-
- // Draw shadows
- gPaint.setARGB(128, 0, 0, 0);
- gPaint.setStyle(Paint.Style.FILL);
-
- // TODO: move to xml file
- canvas.drawRect(0, 0, dWidth, boundsRect.top, gPaint);
- canvas.drawRect(0, boundsRect.bottom, dWidth, dHeight, gPaint);
- canvas.drawRect(0, boundsRect.top, boundsRect.left, boundsRect.bottom,
- gPaint);
- canvas.drawRect(boundsRect.right, boundsRect.top, dWidth,
- boundsRect.bottom, gPaint);
-
- // Draw crop frame
+ // Draw the grid
+ RectF bounds = straightenBounds();
Path path = new Path();
- path.addRect(boundsRect, Path.Direction.CCW);
+ path.addRect(bounds, Path.Direction.CCW);
gPaint.setARGB(255, 255, 255, 255);
gPaint.setStrokeWidth(3);
- gPaint.setStyle(Paint.Style.STROKE);
- canvas.drawPath(path, gPaint);
-
gPaint.setStyle(Paint.Style.FILL_AND_STROKE);
- // Draw grid
+ RectF display = getLocalDisplayBounds();
+ float dWidth = display.width();
+ float dHeight = display.height();
+
if (mMode == MODES.MOVE) {
canvas.save();
canvas.clipPath(path);
+
int n = 16;
float step = dWidth / n;
float p = 0;
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java b/src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java
new file mode 100644
index 000000000..2666cb73d
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageWithIcon.java
@@ -0,0 +1,34 @@
+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/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
index ec0ed7402..42dbcb90e 100644
--- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
@@ -35,6 +35,11 @@ public class ImagePreset {
setup();
}
+ public ImagePreset(ImagePreset source, String historyName) {
+ this(source);
+ if (historyName!=null) setHistoryName(historyName);
+ }
+
public ImagePreset(ImagePreset source) {
try {
if (source.mImageBorder != null) {
@@ -57,7 +62,7 @@ public class ImagePreset {
mGeoData.set(m);
}
- public void setBorder(ImageFilter filter) {
+ private void setBorder(ImageFilter filter) {
mImageBorder = filter;
}
@@ -117,7 +122,38 @@ public class ImagePreset {
}
public void add(ImageFilter filter) {
- mFilters.add(filter);
+
+ if (filter.getFilterType() == ImageFilter.TYPE_BORDER){
+ setHistoryName("Border");
+ setBorder(filter);
+ } else if (filter.getFilterType() == ImageFilter.TYPE_FX){
+
+ boolean found = false;
+ for (int i = 0; i < mFilters.size(); i++) {
+ byte type = mFilters.get(i).getFilterType();
+ if (found) {
+ if (type != ImageFilter.TYPE_VIGNETTE){
+ mFilters.remove(i);
+ continue;
+ }
+ }
+ if (type==ImageFilter.TYPE_FX){
+ mFilters.remove(i);
+ mFilters.add(i, filter);
+ setHistoryName(filter.getName());
+ found = true;
+ }
+
+ }
+ if (!found) {
+ mFilters.add(filter);
+ setHistoryName(filter.getName());
+ }
+ } else {
+ mFilters.add(filter);
+ setHistoryName(filter.getName());
+ }
+
}
public void remove(String filterName) {
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java b/src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java
index 326471ef3..fa207a6d0 100644
--- a/src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java
+++ b/src/com/android/gallery3d/filtershow/presets/ImagePresetFX.java
@@ -22,7 +22,7 @@ public class ImagePresetFX extends ImagePreset {
public void setup() {
if (fxBitmap != null) {
- mFilters.add(new ImageFilterFx(fxBitmap));
+ mFilters.add(new ImageFilterFx(fxBitmap,name));
}
}
diff --git a/src/com/android/gallery3d/filtershow/ui/ImageButtonTitle.java b/src/com/android/gallery3d/filtershow/ui/ImageButtonTitle.java
index 7f0b0437d..51ed7fb20 100644
--- a/src/com/android/gallery3d/filtershow/ui/ImageButtonTitle.java
+++ b/src/com/android/gallery3d/filtershow/ui/ImageButtonTitle.java
@@ -1,16 +1,15 @@
package com.android.gallery3d.filtershow.ui;
-import com.android.gallery3d.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
-import android.util.Log;
import android.widget.ImageButton;
+import com.android.gallery3d.R;
+
public class ImageButtonTitle extends ImageButton {
private static final String LOGTAG = "ImageButtonTitle";
private String mText = null;
@@ -18,6 +17,14 @@ public class ImageButtonTitle extends ImageButton {
private static int mTextPadding = 20;
private static Paint gPaint = new Paint();
+ public static void setTextSize(int value) {
+ mTextSize = value;
+ }
+
+ public static void setTextPadding(int value) {
+ mTextPadding = value;
+ }
+
public ImageButtonTitle(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = getContext().obtainStyledAttributes(
@@ -26,6 +33,7 @@ public class ImageButtonTitle extends ImageButton {
mText = a.getString(R.styleable.ImageButtonTitle_android_text);
}
+ @Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mText != null) {
diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
index fb18bcf8f..660a4fadd 100644
--- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
+++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
@@ -240,17 +240,20 @@ public class ImageCurves extends ImageSlave {
applyNewCurve();
// Log.v(LOGTAG, "ACTION UP, mCurrentControlPoint set to null!");
mCurrentControlPoint = null;
- ImagePreset copy = new ImagePreset(getImagePreset());
-
+ String name = null;
if (mUseRed && mUseGreen && mUseBlue) {
- copy.setHistoryName("Curves (RGB)");
+ name = "Curves (RGB)";
} else if (mUseRed) {
- copy.setHistoryName("Curves (Red)");
+ name = "Curves (Red)";
} else if (mUseGreen) {
- copy.setHistoryName("Curves (Green)");
+ name = "Curves (Green)";
} else if (mUseBlue) {
- copy.setHistoryName("Curves (Blue)");
+ name = "Curves (Blue)";
}
+
+
+ ImagePreset copy = new ImagePreset(getImagePreset(),name);
+
copy.setIsFx(false);
mImageLoader.getHistory().insert(copy, 0);
diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java
index c5aba53f9..8cebdddad 100644
--- a/src/com/android/gallery3d/ui/ActionModeHandler.java
+++ b/src/com/android/gallery3d/ui/ActionModeHandler.java
@@ -227,7 +227,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi
int type = 0;
for (Path path : unexpandedPaths) {
if (jc.isCancelled()) return 0;
- int support = manager.getSupportedOperations(path);
+ int support = manager.getSupportedOperations(path, true);
type |= manager.getMediaType(path);
operation &= support;
}
@@ -297,7 +297,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi
final Intent intent = new Intent();
for (Path path : expandedPaths) {
if (jc.isCancelled()) return null;
- int support = manager.getSupportedOperations(path);
+ int support = manager.getSupportedOperations(path, true);
type |= manager.getMediaType(path);
if ((support & MediaObject.SUPPORT_SHARE) != 0) {
diff --git a/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java b/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java
index 5c246e8e3..d5337f00d 100644
--- a/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java
+++ b/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java
@@ -127,10 +127,10 @@ public class AlbumSetSlotRenderer extends AbstractSlotRenderer {
GLCanvas canvas, int index, AlbumSetEntry entry, int width, int height) {
int renderRequestFlags = 0;
if (entry.album != null && entry.album.isCameraRoll()) {
- int minDim = Math.min(width, height);
- int dim = minDim / 2;
- int pos = (minDim - dim) / 2;
- mCameraOverlay.draw(canvas, pos, pos, dim, dim);
+ int uncoveredHeight = height - mLabelSpec.labelBackgroundHeight;
+ int dim = uncoveredHeight / 2;
+ mCameraOverlay.draw(canvas, (width - dim) / 2,
+ (uncoveredHeight - dim) / 2, dim, dim);
}
if (mPressedIndex == index) {
if (mAnimatePressedUp) {
diff --git a/src/com/android/gallery3d/ui/GLRoot.java b/src/com/android/gallery3d/ui/GLRoot.java
index 1651b4361..13b610b23 100644
--- a/src/com/android/gallery3d/ui/GLRoot.java
+++ b/src/com/android/gallery3d/ui/GLRoot.java
@@ -16,6 +16,7 @@
package com.android.gallery3d.ui;
+import android.content.Context;
import android.graphics.Matrix;
import com.android.gallery3d.anim.CanvasAnimation;
@@ -45,4 +46,6 @@ public interface GLRoot {
public void freeze();
public void unfreeze();
public void setLightsOutMode(boolean enabled);
+
+ public Context getContext();
}
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
index 214d0e017..c6bf535db 100644
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -17,6 +17,7 @@
package com.android.gallery3d.ui;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -546,10 +547,20 @@ public class PhotoView extends GLView {
}
private int getPanoramaRotation() {
- // Panorama only support rotations of 0 and 90, so if it is greater
- // than that flip the output surface texture to compensate
- if (mDisplayRotation > 180)
+ // This function is magic
+ // The issue here is that Pano makes bad assumptions about rotation and
+ // orientation. The first is it assumes only two rotations are possible,
+ // 0 and 90. Thus, if display rotation is >= 180, we invert the output.
+ // The second is that it assumes landscape is a 90 rotation from portrait,
+ // however on landscape devices this is not true. Thus, if we are in portrait
+ // on a landscape device, we need to invert the output
+ int orientation = getGLRoot().getContext().getResources().getConfiguration().orientation;
+ boolean invertPortrait = (orientation == Configuration.ORIENTATION_PORTRAIT
+ && (mDisplayRotation == 90 || mDisplayRotation == 270));
+ boolean invert = (mDisplayRotation >= 180);
+ if (invert != invertPortrait) {
return (mCompensation + 180) % 360;
+ }
return mCompensation;
}
@@ -1318,6 +1329,7 @@ public class PhotoView extends GLView {
public void resume() {
mTileView.prepareTextures();
+ mPositionController.skipToFinalPosition();
}
// move to the camera preview and show controls after resume
diff --git a/src_pd/com/android/gallery3d/util/LightCycleHelper.java b/src_pd/com/android/gallery3d/util/LightCycleHelper.java
index cc8ea20b9..995eac8b1 100644
--- a/src_pd/com/android/gallery3d/util/LightCycleHelper.java
+++ b/src_pd/com/android/gallery3d/util/LightCycleHelper.java
@@ -27,13 +27,20 @@ import com.android.gallery3d.app.GalleryApp;
import com.android.gallery3d.app.StitchingProgressManager;
public class LightCycleHelper {
+ public static class PanoramaMetadata {
+ // Whether a panorama viewer should be used
+ public final boolean mUsePanoramaViewer;
+ // Whether a panorama is 360 degrees
+ public final boolean mIsPanorama360;
- public static void setupCaptureIntent(Context context, Intent it, String outputDir) {
- /* Do nothing */
+ public PanoramaMetadata(boolean usePanoramaViewer, boolean isPanorama360) {
+ mUsePanoramaViewer = usePanoramaViewer;
+ mIsPanorama360 = isPanorama360;
+ }
}
- public static boolean hasLightCycleView(Context context) {
- return false;
+ public static void setupCaptureIntent(Context context, Intent it, String outputDir) {
+ /* Do nothing */
}
public static boolean hasLightCycleCapture(Context context) {
@@ -44,12 +51,8 @@ public class LightCycleHelper {
/* Do nothing */
}
- public static boolean isPanorama(ContentResolver contentResolver, Uri uri) {
- return false;
- }
-
- public static boolean isPanorama360(Context context, Uri uri) {
- return false;
+ public static PanoramaMetadata getPanoramaMetadata(Context context, Uri uri) {
+ return null;
}
public static CameraModule createPanoramaModule() {
diff --git a/tests/src/com/android/gallery3d/ui/GLRootMock.java b/tests/src/com/android/gallery3d/ui/GLRootMock.java
index 467edfc7f..b1c4355d0 100644
--- a/tests/src/com/android/gallery3d/ui/GLRootMock.java
+++ b/tests/src/com/android/gallery3d/ui/GLRootMock.java
@@ -16,6 +16,7 @@
package com.android.gallery3d.ui;
+import android.content.Context;
import android.graphics.Matrix;
import com.android.gallery3d.anim.CanvasAnimation;
@@ -42,4 +43,5 @@ public class GLRootMock implements GLRoot {
public void freeze() {}
public void unfreeze() {}
public void setLightsOutMode(boolean enabled) {}
+ public Context getContext() { return null; }
}
diff --git a/tests/src/com/android/gallery3d/ui/GLRootStub.java b/tests/src/com/android/gallery3d/ui/GLRootStub.java
index 0f3a00164..7f134dbf1 100644
--- a/tests/src/com/android/gallery3d/ui/GLRootStub.java
+++ b/tests/src/com/android/gallery3d/ui/GLRootStub.java
@@ -16,6 +16,7 @@
package com.android.gallery3d.ui;
+import android.content.Context;
import android.graphics.Matrix;
import com.android.gallery3d.anim.CanvasAnimation;
@@ -35,4 +36,5 @@ public class GLRootStub implements GLRoot {
public void freeze() {}
public void unfreeze() {}
public void setLightsOutMode(boolean enabled) {}
+ public Context getContext() { return null; }
}