summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/filtershow
diff options
context:
space:
mode:
authornicolasroard <nicolasroard@google.com>2013-01-15 19:57:49 -0800
committernicolasroard <nicolasroard@google.com>2013-01-22 16:05:42 -0800
commit87463e150b1f52086ecf7d597636ba83e7f93b8f (patch)
tree133476d61d99de60e9feb0b2ee1baa60dcbf3ac3 /src/com/android/gallery3d/filtershow
parentfd2c62cbf84fcdaa3280327fd02f4372b3118338 (diff)
downloadandroid_packages_apps_Snap-87463e150b1f52086ecf7d597636ba83e7f93b8f.tar.gz
android_packages_apps_Snap-87463e150b1f52086ecf7d597636ba83e7f93b8f.tar.bz2
android_packages_apps_Snap-87463e150b1f52086ecf7d597636ba83e7f93b8f.zip
Better caching for RS filters
Change-Id: I78eaa90e408059cf1c59fc06920f5aef82ae2c0d
Diffstat (limited to 'src/com/android/gallery3d/filtershow')
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java17
-rw-r--r--src/com/android/gallery3d/filtershow/PanelController.java3
-rw-r--r--src/com/android/gallery3d/filtershow/cache/DelayedPresetCache.java75
-rw-r--r--src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java183
-rw-r--r--src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java298
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java61
-rw-r--r--src/com/android/gallery3d/filtershow/cache/TripleBufferBitmap.java71
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilter.java10
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java44
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java1
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java16
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java1
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/MasterImage.java94
-rw-r--r--src/com/android/gallery3d/filtershow/presets/ImagePreset.java87
14 files changed, 562 insertions, 399 deletions
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 376538086..1e2bad34e 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -220,9 +220,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mImageViews.add(mImageFlip);
mImageViews.add(mImageTinyPlanet);
mImageViews.add(mImageRedEyes);
- for (ImageShow imageShow : mImageViews) {
- mImageLoader.addCacheListener(imageShow);
- }
mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer));
EditorManager.addEditors(mEditorPlaceHolder);
@@ -961,14 +958,18 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
if (mMasterImage.getCurrentFilter() == filter) {
return;
}
- mMasterImage.setCurrentFilter(filter);
- ImagePreset oldPreset = mImageShow.getImagePreset();
+ ImagePreset oldPreset = mMasterImage.getPreset();
ImagePreset copy = new ImagePreset(oldPreset);
+ mMasterImage.setPreset(copy, true);
// TODO: use a numerical constant instead.
- copy.add(filter);
-
- mMasterImage.setPreset(copy, true);
+ ImagePreset current = mMasterImage.getPreset();
+ ImageFilter existingFilter = current.getFilter(filter.getName());
+ if (existingFilter == null) {
+ current.add(filter);
+ }
+ existingFilter = current.getFilter(filter.getName());
+ mMasterImage.setCurrentFilter(existingFilter);
invalidateViews();
}
diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java
index 7f99218de..a0b13fb84 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -483,7 +483,8 @@ public class PanelController implements OnClickListener {
mUtilityPanel.setEffectName(ename);
mUtilityPanel.setShowParameter(filter.showParameterValue());
- mMasterImage.setCurrentFilter(filter);
+ ImageFilter currentFilter = mMasterImage.getPreset().getFilter(filter.getName());
+ mMasterImage.setCurrentFilter(currentFilter);
mCurrentImage.select();
if (mCurrentEditor != null) {
mCurrentEditor.reflectCurrentFilter();
diff --git a/src/com/android/gallery3d/filtershow/cache/DelayedPresetCache.java b/src/com/android/gallery3d/filtershow/cache/DelayedPresetCache.java
deleted file mode 100644
index 408ba5912..000000000
--- a/src/com/android/gallery3d/filtershow/cache/DelayedPresetCache.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.gallery3d.filtershow.cache;
-
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.os.Process;
-
-public class DelayedPresetCache extends DirectPresetCache implements Callback {
- private HandlerThread mHandlerThread = null;
-
- private final static int NEW_PRESET = 0;
- private final static int COMPUTE_PRESET = 1;
-
- private Handler mProcessingHandler = null;
- private final Handler mUIHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case NEW_PRESET: {
- CachedPreset cache = (CachedPreset) msg.obj;
- didCompute(cache);
- break;
- }
- }
- }
- };
-
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case COMPUTE_PRESET: {
- CachedPreset cache = (CachedPreset) msg.obj;
- compute(cache);
- Message uimsg = mUIHandler.obtainMessage(NEW_PRESET, cache);
- mUIHandler.sendMessage(uimsg);
- break;
- }
- }
- return false;
- }
-
- public DelayedPresetCache(ImageLoader loader, int size) {
- super(loader, size);
- mHandlerThread = new HandlerThread("ImageProcessing", Process.THREAD_PRIORITY_BACKGROUND);
- mHandlerThread.start();
- mProcessingHandler = new Handler(mHandlerThread.getLooper(), this);
- }
-
- @Override
- protected void willCompute(CachedPreset cache) {
- if (cache == null) {
- return;
- }
- cache.setBusy(true);
- Message msg = mProcessingHandler.obtainMessage(COMPUTE_PRESET, cache);
- mProcessingHandler.sendMessage(msg);
- }
-}
diff --git a/src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java b/src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java
deleted file mode 100644
index d58e953c2..000000000
--- a/src/com/android/gallery3d/filtershow/cache/DirectPresetCache.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.gallery3d.filtershow.cache;
-
-import android.graphics.Bitmap;
-
-import com.android.gallery3d.filtershow.imageshow.ImageShow;
-import com.android.gallery3d.filtershow.imageshow.MasterImage;
-import com.android.gallery3d.filtershow.presets.ImagePreset;
-
-import java.util.Vector;
-
-public class DirectPresetCache implements Cache {
-
- private static final String LOGTAG = "DirectPresetCache";
- private Bitmap mOriginalBitmap = null;
- private final Vector<ImageShow> mObservers = new Vector<ImageShow>();
- private final Vector<CachedPreset> mCache = new Vector<CachedPreset>();
- private int mCacheSize = 1;
- private final Bitmap.Config mBitmapConfig = Bitmap.Config.ARGB_8888;
- private long mGlobalAge = 0;
- private ImageLoader mLoader = null;
-
- protected class CachedPreset {
- private Bitmap mBitmap = null;
- private ImagePreset mPreset = null;
- private long mAge = 0;
- private boolean mBusy = false;
-
- public void setBusy(boolean value) {
- mBusy = value;
- }
-
- public boolean busy() {
- return mBusy;
- }
- }
-
- public DirectPresetCache(ImageLoader loader, int size) {
- mLoader = loader;
- mCacheSize = size;
- }
-
- @Override
- public void setOriginalBitmap(Bitmap bitmap) {
- mOriginalBitmap = bitmap;
- notifyObservers();
- }
-
- public void notifyObservers() {
- mLoader.getActivity().runOnUiThread(mNotifyObserversRunnable);
- }
-
- private final Runnable mNotifyObserversRunnable = new Runnable() {
- @Override
- public void run() {
- for (int i = 0; i < mObservers.size(); i++) {
- ImageShow imageShow = mObservers.elementAt(i);
- // FIXME: need to replace the observer from ImageShow to
- // MasterImage
- if (imageShow != null) {
- imageShow.invalidate();
- imageShow.updateImage();
- }
- MasterImage.getImage().updatedCache();
- }
- }
- };
-
- @Override
- public void addObserver(ImageShow observer) {
- if (!mObservers.contains(observer)) {
- mObservers.add(observer);
- }
- }
-
- private CachedPreset getCachedPreset(ImagePreset preset) {
- for (int i = 0; i < mCache.size(); i++) {
- CachedPreset cache = mCache.elementAt(i);
- if (cache.mPreset == preset) {
- return cache;
- }
- }
- return null;
- }
-
- @Override
- public Bitmap get(ImagePreset preset) {
- CachedPreset cache = getCachedPreset(preset);
- if (cache != null && !cache.mBusy) {
- return cache.mBitmap;
- }
- return null;
- }
-
- @Override
- public void reset(ImagePreset preset) {
- CachedPreset cache = getCachedPreset(preset);
- if (cache != null && !cache.mBusy) {
- cache.mBitmap = null;
- willCompute(cache);
- }
- }
-
- private CachedPreset getOldestCachedPreset() {
- CachedPreset found = null;
- for (int i = 0; i < mCache.size(); i++) {
- CachedPreset cache = mCache.elementAt(i);
- if (cache.mBusy) {
- continue;
- }
- if (found == null) {
- found = cache;
- } else {
- if (found.mAge > cache.mAge) {
- found = cache;
- }
- }
- }
- return found;
- }
-
- protected void willCompute(CachedPreset cache) {
- if (cache == null) {
- return;
- }
- cache.mBusy = true;
- compute(cache);
- didCompute(cache);
- }
-
- protected void didCompute(CachedPreset cache) {
- cache.mBusy = false;
- notifyObservers();
- }
-
- protected void compute(CachedPreset cache) {
- cache.mBitmap = null;
- cache.mBitmap = mOriginalBitmap.copy(mBitmapConfig, true);
- float scaleFactor = (float) cache.mBitmap.getWidth() / (float) mLoader.getOriginalBounds().width();
- if (scaleFactor < 1.0f) {
- cache.mPreset.setIsHighQuality(false);
- }
- cache.mPreset.setScaleFactor(scaleFactor);
- cache.mBitmap = cache.mPreset.apply(cache.mBitmap);
- cache.mAge = mGlobalAge++;
- }
-
- @Override
- public void prepare(ImagePreset preset) {
- CachedPreset cache = getCachedPreset(preset);
- 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);
- }
- }
-
- }
-
-}
diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
new file mode 100644
index 000000000..a1dbe8e52
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.cache;
+
+import android.graphics.Bitmap;
+import android.os.*;
+import android.os.Process;
+import android.renderscript.Allocation;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.RenderScript;
+import android.util.Log;
+
+import com.android.gallery3d.filtershow.filters.ImageFilterRS;
+import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.presets.ImagePreset;
+
+public class FilteringPipeline implements Handler.Callback {
+
+ private final static FilteringPipeline gPipeline = new FilteringPipeline();
+ private static final String LOGTAG = "FilteringPipeline";
+ private ImagePreset mPreviousPreset = null;
+ private ImagePreset mPreviousGeometryPreset = null;
+ private ImagePreset mPreviousFiltersPreset = null;
+ private GeometryMetadata mPreviousGeometry = null;
+
+ private Bitmap mOriginalBitmap = null;
+ private Bitmap mResizedOriginalBitmap = null;
+
+ private boolean DEBUG = false;
+
+ private HandlerThread mHandlerThread = null;
+ private final static int NEW_PRESET = 0;
+ private final static int COMPUTE_PRESET = 1;
+ private final static int COMPUTE_GEOMETRY_PRESET = 2;
+ private final static int COMPUTE_FILTERS_PRESET = 3;
+
+ private boolean mProcessing = false;
+
+ private Handler mProcessingHandler = null;
+ private final Handler mUIHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case NEW_PRESET: {
+ MasterImage.getImage().notifyObservers();
+ mProcessing = false;
+ break;
+ }
+ }
+ }
+ };
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case COMPUTE_PRESET: {
+ ImagePreset preset = MasterImage.getImage().getPreset();
+ TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer();
+ compute(buffer, preset, COMPUTE_PRESET);
+ Message uimsg = mUIHandler.obtainMessage(NEW_PRESET);
+ mUIHandler.sendMessage(uimsg);
+ break;
+ }
+ case COMPUTE_GEOMETRY_PRESET: {
+ ImagePreset preset = MasterImage.getImage().getGeometryPreset();
+ TripleBufferBitmap buffer = MasterImage.getImage().getGeometryOnlyBuffer();
+ compute(buffer, preset, COMPUTE_GEOMETRY_PRESET);
+ Message uimsg = mUIHandler.obtainMessage(NEW_PRESET);
+ mUIHandler.sendMessage(uimsg);
+ break;
+ }
+ case COMPUTE_FILTERS_PRESET: {
+ ImagePreset preset = MasterImage.getImage().getFiltersOnlyPreset();
+ TripleBufferBitmap buffer = MasterImage.getImage().getFiltersOnlyBuffer();
+ compute(buffer, preset, COMPUTE_FILTERS_PRESET);
+ Message uimsg = mUIHandler.obtainMessage(NEW_PRESET);
+ mUIHandler.sendMessage(uimsg);
+ break;
+ }
+ }
+ return false;
+ }
+
+ private static float RESIZE_FACTOR = 0.8f;
+ private static float MAX_PROCESS_TIME = 100; // in ms
+ private float mResizeFactor = 1.0f;
+ private long mResizeTime = 0;
+
+ private Allocation mOriginalBitmapAllocation = null;
+ private Allocation mOriginalAllocation = null;
+ private Allocation mFiltersOnlyOriginalAllocation = null;
+
+ private FilteringPipeline() {
+ mHandlerThread = new HandlerThread("FilteringPipeline",
+ Process.THREAD_PRIORITY_FOREGROUND);
+ mHandlerThread.start();
+ mProcessingHandler = new Handler(mHandlerThread.getLooper(), this);
+ }
+
+ public static FilteringPipeline getPipeline() {
+ return gPipeline;
+ }
+
+ public synchronized void setOriginal(Bitmap bitmap) {
+ mOriginalBitmap = bitmap;
+ Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight());
+ updateOriginalAllocation(MasterImage.getImage().getPreset());
+ }
+
+ public synchronized boolean updateOriginalAllocation(ImagePreset preset) {
+ if (mOriginalBitmap == null) {
+ return false;
+ }
+ /*
+ //FIXME: turn back on the on-the-fly resize.
+ int w = (int) (mOriginalBitmap.getWidth() * mResizeFactor);
+ int h = (int) (mOriginalBitmap.getHeight() * mResizeFactor);
+ if (!needsGeometryRepaint() && mResizedOriginalBitmap != null && w == mResizedOriginalBitmap.getWidth()) {
+ return false;
+ }
+ mResizedOriginalBitmap = Bitmap.createScaledBitmap(mOriginalBitmap, w, h, true);
+ */
+ GeometryMetadata geometry = preset.getGeometry();
+ if (mPreviousGeometry != null && geometry.equals(mPreviousGeometry)) {
+ return false;
+ }
+ RenderScript RS = ImageFilterRS.getRenderScriptContext();
+ if (mFiltersOnlyOriginalAllocation != null) {
+ mFiltersOnlyOriginalAllocation.destroy();
+ }
+ mFiltersOnlyOriginalAllocation = Allocation.createFromBitmap(RS, mOriginalBitmap,
+ MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
+ if (mOriginalAllocation != null) {
+ mOriginalAllocation.destroy();
+ }
+ mResizedOriginalBitmap = preset.applyGeometry(mOriginalBitmap);
+ mOriginalAllocation = Allocation.createFromBitmap(RS, mResizedOriginalBitmap,
+ MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
+ mPreviousGeometry = new GeometryMetadata(geometry);
+ return true;
+ }
+
+ public synchronized void updatePreviewBuffer() {
+ if (mOriginalAllocation == null) {
+ return;
+ }
+ if (mProcessing) {
+ return;
+ }
+ if (mProcessingHandler.hasMessages(COMPUTE_PRESET)) {
+ return;
+ }
+ if (!needsRepaint()) {
+ return;
+ }
+ Message msg = mProcessingHandler.obtainMessage(COMPUTE_PRESET);
+ mProcessingHandler.sendMessage(msg);
+ mProcessing = true;
+ }
+
+ public void updateGeometryOnlyPreviewBuffer() {
+ if (mOriginalAllocation == null) {
+ return;
+ }
+ if (mProcessing) {
+ return;
+ }
+ if (mProcessingHandler.hasMessages(COMPUTE_GEOMETRY_PRESET)) {
+ return;
+ }
+ if (!needsGeometryRepaint()) {
+ return;
+ }
+ Message msg = mProcessingHandler.obtainMessage(COMPUTE_GEOMETRY_PRESET);
+ mProcessingHandler.sendMessage(msg);
+ mProcessing = true;
+ }
+
+ public void updateFiltersOnlyPreviewBuffer() {
+ if (mOriginalAllocation == null) {
+ return;
+ }
+ if (mProcessing) {
+ return;
+ }
+ if (mProcessingHandler.hasMessages(COMPUTE_FILTERS_PRESET)) {
+ return;
+ }
+ if (!needsFiltersRepaint()) {
+ return;
+ }
+ Message msg = mProcessingHandler.obtainMessage(COMPUTE_FILTERS_PRESET);
+ mProcessingHandler.sendMessage(msg);
+ mProcessing = true;
+ }
+
+ private void compute(TripleBufferBitmap buffer, ImagePreset preset, int type) {
+ String thread = Thread.currentThread().getName();
+ long time = System.currentTimeMillis();
+ if (updateOriginalAllocation(preset)) {
+ buffer.updateBitmaps(mResizedOriginalBitmap);
+ }
+ Bitmap bitmap = buffer.getProducer();
+ long time2 = System.currentTimeMillis();
+
+ if (type != COMPUTE_FILTERS_PRESET) {
+ if (bitmap == null || (bitmap.getWidth() != mResizedOriginalBitmap.getWidth())
+ || (bitmap.getHeight() != mResizedOriginalBitmap.getHeight())) {
+ buffer.updateBitmaps(mResizedOriginalBitmap);
+ bitmap = buffer.getProducer();
+ }
+ mOriginalAllocation.copyTo(bitmap);
+ } else {
+ if (bitmap == null || (bitmap.getWidth() != mOriginalBitmap.getWidth())
+ || (bitmap.getHeight() != mOriginalBitmap.getHeight())) {
+ buffer.updateBitmaps(mOriginalBitmap);
+ bitmap = buffer.getProducer();
+ }
+ mFiltersOnlyOriginalAllocation.copyTo(bitmap);
+ }
+
+ if (mOriginalAllocation == null || bitmap == null) {
+ Log.v(LOGTAG, "exiting compute because mOriginalAllocation: " + mOriginalAllocation + " or bitmap: " + bitmap);
+ return;
+ }
+
+ if (type != COMPUTE_GEOMETRY_PRESET) {
+ bitmap = preset.apply(bitmap);
+ }
+
+ buffer.swapProducer();
+ time = System.currentTimeMillis() - time;
+ time2 = System.currentTimeMillis() - time2;
+ if (DEBUG) {
+ Log.v(LOGTAG, "Applying " + type + " filters to bitmap " + bitmap + " took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread);
+ }
+ if (type == COMPUTE_PRESET) {
+ mPreviousPreset = new ImagePreset(preset);
+ if (mResizeFactor > 0.6 && time > MAX_PROCESS_TIME && (System.currentTimeMillis() + 1000 > mResizeTime)) {
+ mResizeTime = System.currentTimeMillis();
+ mResizeFactor *= RESIZE_FACTOR;
+ }
+ } else if (type == COMPUTE_GEOMETRY_PRESET) {
+ mPreviousGeometryPreset = new ImagePreset(preset);
+ } else if (type == COMPUTE_FILTERS_PRESET) {
+ mPreviousFiltersPreset = new ImagePreset(preset);
+ }
+ }
+
+ private synchronized boolean needsRepaint() {
+ ImagePreset preset = MasterImage.getImage().getPreset();
+ if (preset == null || mPreviousPreset == null) {
+ return true;
+ }
+ if (preset.equals(mPreviousPreset)) {
+ return false;
+ }
+ return true;
+ }
+
+ private synchronized boolean needsGeometryRepaint() {
+ ImagePreset preset = MasterImage.getImage().getPreset();
+ if (preset == null || mPreviousGeometry == null || mPreviousGeometryPreset == null) {
+ return true;
+ }
+ GeometryMetadata geometry = preset.getGeometry();
+ if (geometry.equals(mPreviousGeometryPreset.getGeometry())) {
+ return false;
+ }
+ return true;
+ }
+
+ private synchronized boolean needsFiltersRepaint() {
+ ImagePreset preset = MasterImage.getImage().getPreset();
+ if (preset == null || mPreviousFiltersPreset == null) {
+ return true;
+ }
+ if (preset.equals(mPreviousFiltersPreset)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 2c5bc1df9..85d0977e7 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -70,8 +70,6 @@ public class ImageLoader {
private Bitmap mOriginalBitmapLarge = null;
private Bitmap mBackgroundBitmap = null;
- private Cache mCache = null;
- private Cache mHiresCache = null;
private final ZoomCache mZoomCache = new ZoomCache();
private int mOrientation = 0;
@@ -104,8 +102,6 @@ public class ImageLoader {
public ImageLoader(FilterShowActivity activity, Context context) {
mActivity = activity;
mContext = context;
- mCache = new DelayedPresetCache(this, 30);
- mHiresCache = new DelayedPresetCache(this, 3);
}
public static int getZoomOrientation() {
@@ -216,8 +212,7 @@ public class ImageLoader {
mOriginalBitmapLarge = rotateToPortrait(mOriginalBitmapLarge, mOrientation);
}
mZoomOrientation = mOrientation;
- mCache.setOriginalBitmap(mOriginalBitmapSmall);
- mHiresCache.setOriginalBitmap(mOriginalBitmapLarge);
+ FilteringPipeline.getPipeline().setOriginal(mOriginalBitmapLarge);
warnListeners();
}
@@ -350,7 +345,6 @@ public class ImageLoader {
if (!mListeners.contains(imageShow)) {
mListeners.add(imageShow);
}
- mHiresCache.addObserver(imageShow);
mLoadingLock.unlock();
}
@@ -369,9 +363,8 @@ public class ImageLoader {
}
};
- // TODO: this currently does the loading + filtering on the UI thread --
- // need to
- // move this to a background thread.
+ // FIXME: this currently does the loading + filtering on the UI thread --
+ // need to move this to a background thread.
public Bitmap getScaleOneImageForPreset(ImageShow caller, ImagePreset imagePreset, Rect bounds,
boolean force) {
mLoadingLock.lock();
@@ -394,48 +387,6 @@ public class ImageLoader {
return bmp;
}
- // Caching method
- public Bitmap getImageForPreset(ImageShow caller, ImagePreset imagePreset,
- boolean hiRes) {
- mLoadingLock.lock();
- if (mOriginalBitmapSmall == null) {
- mLoadingLock.unlock();
- return null;
- }
- if (mOriginalBitmapLarge == null) {
- mLoadingLock.unlock();
- return null;
- }
-
- Bitmap filteredImage = null;
-
- if (hiRes) {
- filteredImage = mHiresCache.get(imagePreset);
- } else {
- filteredImage = mCache.get(imagePreset);
- }
-
- if (filteredImage == null) {
- if (hiRes) {
- mHiresCache.prepare(imagePreset);
- mHiresCache.addObserver(caller);
- } else {
- mCache.prepare(imagePreset);
- mCache.addObserver(caller);
- }
- }
- mLoadingLock.unlock();
- return filteredImage;
- }
-
- public void resetImageForPreset(ImagePreset imagePreset, ImageShow caller) {
- mLoadingLock.lock();
- mHiresCache.reset(imagePreset);
- mCache.reset(imagePreset);
- mZoomCache.reset(imagePreset);
- mLoadingLock.unlock();
- }
-
public void saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity,
File destination) {
preset.setIsHighQuality(true);
@@ -624,10 +575,4 @@ public class ImageLoader {
Utils.closeSilently(is);
}
}
-
- public void addCacheListener(ImageShow imageShow) {
- mHiresCache.addObserver(imageShow);
- mCache.addObserver(imageShow);
- }
-
}
diff --git a/src/com/android/gallery3d/filtershow/cache/TripleBufferBitmap.java b/src/com/android/gallery3d/filtershow/cache/TripleBufferBitmap.java
new file mode 100644
index 000000000..c4837ad4a
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/cache/TripleBufferBitmap.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.cache;
+
+import android.graphics.Bitmap;
+import com.android.gallery3d.app.Log;
+
+public class TripleBufferBitmap {
+
+ private static String LOGTAG = "TripleBufferBitmap";
+
+ private Bitmap mBitmaps[] = new Bitmap[3];
+ private Bitmap mProducer = null;
+ private Bitmap mConsumer = null;
+ private Bitmap mIntermediate = null;
+ private boolean mNeedsSwap = false;
+
+ private final Bitmap.Config mBitmapConfig = Bitmap.Config.ARGB_8888;
+
+ public TripleBufferBitmap() {
+
+ }
+
+ public synchronized void updateBitmaps(Bitmap bitmap) {
+ mBitmaps[0] = bitmap.copy(mBitmapConfig, true);
+ mBitmaps[1] = bitmap.copy(mBitmapConfig, true);
+ mBitmaps[2] = bitmap.copy(mBitmapConfig, true);
+ mProducer = mBitmaps[0];
+ mConsumer = mBitmaps[1];
+ mIntermediate = mBitmaps[2];
+ }
+
+ public synchronized Bitmap getProducer() {
+ return mProducer;
+ }
+
+ public synchronized Bitmap getConsumer() {
+ return mConsumer;
+ }
+
+ public synchronized void swapProducer() {
+ Bitmap intermediate = mIntermediate;
+ mIntermediate = mProducer;
+ mProducer = intermediate;
+ mNeedsSwap = true;
+ }
+
+ public synchronized void swapConsumer() {
+ if (!mNeedsSwap) {
+ return;
+ }
+ Bitmap intermediate = mIntermediate;
+ mIntermediate = mConsumer;
+ mConsumer = intermediate;
+ mNeedsSwap = false;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index db74cc8bc..96f98d5b1 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -179,6 +179,16 @@ public class ImageFilter implements Cloneable {
this.mImagePreset = mPreset;
}
+ public boolean equals(ImageFilter filter) {
+ if (!same(filter)) {
+ return false;
+ }
+ if (mParameter != filter.mParameter) {
+ return false;
+ }
+ return true;
+ }
+
public boolean same(ImageFilter filter) {
if (filter == null) {
return false;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
index 6f7c36e28..63dc82c34 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
@@ -19,6 +19,7 @@ package com.android.gallery3d.filtershow.filters;
import android.app.Activity;
import android.graphics.Bitmap;
import android.renderscript.Allocation;
+import android.renderscript.Allocation.MipmapControl;
import android.renderscript.RenderScript;
import android.util.Log;
@@ -29,25 +30,43 @@ public class ImageFilterRS extends ImageFilter {
protected static Allocation mInPixelsAllocation;
protected static Allocation mOutPixelsAllocation;
private static android.content.res.Resources mResources = null;
+ private static Bitmap sOldBitmap = null;
+ private Bitmap mOldBitmap = null;
- public void prepare(Bitmap bitmap) {
- if (mInPixelsAllocation != null) {
- mInPixelsAllocation.destroy();
+ private static Bitmap mReturnBitmap = null;
+ private final Bitmap.Config mBitmapConfig = Bitmap.Config.ARGB_8888;
+
+ public void prepare(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+ if (sOldBitmap == null
+ || (bitmap.getWidth() != sOldBitmap.getWidth())
+ || (bitmap.getHeight() != sOldBitmap.getHeight())) {
+ if (mInPixelsAllocation != null) {
+ mInPixelsAllocation.destroy();
+ }
+ if (mOutPixelsAllocation != null) {
+ mOutPixelsAllocation.destroy();
+ }
+ Bitmap bitmapBuffer = bitmap.copy(mBitmapConfig, true);
+ mOutPixelsAllocation = Allocation.createFromBitmap(mRS, bitmapBuffer,
+ MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
+ mInPixelsAllocation = Allocation.createTyped(mRS,
+ mOutPixelsAllocation.getType());
+ sOldBitmap = bitmap;
}
- if (mOutPixelsAllocation != null) {
- mOutPixelsAllocation.destroy();
+ mInPixelsAllocation.copyFrom(bitmap);
+ if (mOldBitmap != sOldBitmap) {
+ createFilter(mResources, scaleFactor, highQuality);
+ mOldBitmap = sOldBitmap;
}
- mInPixelsAllocation = Allocation.createFromBitmap(mRS, bitmap,
- Allocation.MipmapControl.MIPMAP_NONE,
- Allocation.USAGE_SCRIPT);
- mOutPixelsAllocation = Allocation.createTyped(mRS, mInPixelsAllocation.getType());
}
- public void createFilter(android.content.res.Resources res, float scaleFactor,
- boolean highQuality) {
+ public void createFilter(android.content.res.Resources res,
+ float scaleFactor, boolean highQuality) {
+ // Stub
}
public void runFilter() {
+ // Stub
}
public void update(Bitmap bitmap) {
@@ -60,8 +79,7 @@ public class ImageFilterRS extends ImageFilter {
return bitmap;
}
try {
- prepare(bitmap);
- createFilter(mResources, scaleFactor, highQuality);
+ prepare(bitmap, scaleFactor, highQuality);
runFilter();
update(bitmap);
} catch (android.renderscript.RSIllegalArgumentException e) {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java b/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
index 588fa9aa9..3d73ef686 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageGeometry.java
@@ -415,7 +415,6 @@ public abstract class ImageGeometry extends ImageShow {
syncLocalToMasterGeometry();
clearDirtyGeometryFlag();
}
- requestFilteredImages();
Bitmap image = getFiltersOnlyImage();
if (image == null) {
invalidate();
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 3d22e05ef..93c4622fa 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -198,12 +198,14 @@ public class ImageShow extends View implements OnGestureListener,
int maxp = ImageFilter.DEFAULT_MAX_PARAMETER;
int minp = ImageFilter.DEFAULT_MIN_PARAMETER;
if (getCurrentFilter() != null) {
+ if (getCurrentFilter().getParameter() == parameter) {
+ return;
+ }
getCurrentFilter().setParameter(parameter);
maxp = getCurrentFilter().getMaxParameter();
minp = getCurrentFilter().getMinParameter();
}
if (getImagePreset() != null) {
- mImageLoader.resetImageForPreset(getImagePreset(), this);
getImagePreset().fillImageStateAdapter(mMasterImage.getState());
}
if (getPanelController() != null) {
@@ -255,10 +257,6 @@ public class ImageShow extends View implements OnGestureListener,
mSeekBar = seekBar;
}
- public void setCurrentFilter(ImageFilter filter) {
- mMasterImage.setCurrentFilter(filter);
- }
-
public ImageFilter getCurrentFilter() {
return mMasterImage.getCurrentFilter();
}
@@ -355,14 +353,6 @@ public class ImageShow extends View implements OnGestureListener,
mMasterImage.updatePresets(true);
}
- public void updateImagePresets(boolean force) {
- mMasterImage.updatePresets(force);
- }
-
- public void requestFilteredImages() {
- mMasterImage.requestImages();
- }
-
public Bitmap getFiltersOnlyImage() {
return mMasterImage.getFiltersOnlyImage();
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
index e45b7b4dc..222519c11 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
@@ -98,7 +98,6 @@ public class ImageZoom extends ImageShow {
filteredImage = mImageLoader.getScaleOneImageForPreset(this, getImagePreset(),
mZoomBounds, false);
} else {
- requestFilteredImages();
filteredImage = getFilteredImage();
}
canvas.save();
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index 98bef52c7..f4b97b710 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -1,13 +1,29 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.gallery3d.filtershow.imageshow;
import android.graphics.Bitmap;
import android.graphics.RectF;
-import android.util.Log;
-import android.widget.ArrayAdapter;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.HistoryAdapter;
import com.android.gallery3d.filtershow.ImageStateAdapter;
+import com.android.gallery3d.filtershow.cache.TripleBufferBitmap;
+import com.android.gallery3d.filtershow.cache.FilteringPipeline;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.presets.ImagePreset;
@@ -25,9 +41,9 @@ public class MasterImage {
private ImagePreset mGeometryOnlyPreset = null;
private ImagePreset mFiltersOnlyPreset = null;
- private Bitmap mGeometryOnlyImage = null;
- private Bitmap mFiltersOnlyImage = null;
- private Bitmap mFilteredImage = null;
+ private TripleBufferBitmap mFilteredPreview = new TripleBufferBitmap();
+ private TripleBufferBitmap mGeometryOnlyPreview = new TripleBufferBitmap();
+ private TripleBufferBitmap mFiltersOnlyPreview = new TripleBufferBitmap();
private ImageLoader mLoader = null;
private HistoryAdapter mHistory = null;
@@ -37,8 +53,7 @@ public class MasterImage {
private Vector<ImageShow> mObservers = new Vector<ImageShow>();
- private MasterImage() {
- }
+ private MasterImage() { }
public static MasterImage getImage() {
return sMasterImage;
@@ -52,11 +67,19 @@ public class MasterImage {
mActivity = activity;
}
- public ImagePreset getPreset() {
+ public synchronized ImagePreset getPreset() {
return mPreset;
}
- public void setPreset(ImagePreset preset, boolean addToHistory) {
+ public synchronized ImagePreset getGeometryPreset() {
+ return mGeometryOnlyPreset;
+ }
+
+ public synchronized ImagePreset getFiltersOnlyPreset() {
+ return mFiltersOnlyPreset;
+ }
+
+ public synchronized void setPreset(ImagePreset preset, boolean addToHistory) {
mPreset = preset;
mPreset.setImageLoader(mLoader);
setGeometry();
@@ -118,29 +141,45 @@ public class MasterImage {
return mCurrentFilter;
}
- public boolean hasModifications() {
+ public synchronized boolean hasModifications() {
if (mPreset == null) {
return false;
}
return mPreset.hasModifications();
}
+ public TripleBufferBitmap getDoubleBuffer() {
+ return mFilteredPreview;
+ }
+
+ public TripleBufferBitmap getGeometryOnlyBuffer() {
+ return mGeometryOnlyPreview;
+ }
+
+ public TripleBufferBitmap getFiltersOnlyBuffer() {
+ return mFiltersOnlyPreview;
+ }
+
public Bitmap getFilteredImage() {
requestImages();
- return mFilteredImage;
+ mFilteredPreview.swapConsumer();
+ return mFilteredPreview.getConsumer();
}
public Bitmap getFiltersOnlyImage() {
requestImages();
- return mFiltersOnlyImage;
+ mFiltersOnlyPreview.swapConsumer();
+ return mFiltersOnlyPreview.getConsumer();
}
public Bitmap getGeometryOnlyImage() {
requestImages();
- return mGeometryOnlyImage;
+ mGeometryOnlyPreview.swapConsumer();
+ return mGeometryOnlyPreview.getConsumer();
}
- private void notifyObservers() {
+ public void notifyObservers() {
+ requestImages();
for (ImageShow observer : mObservers) {
observer.invalidate();
}
@@ -152,16 +191,12 @@ public class MasterImage {
}
public void updatePresets(boolean force) {
- if (force) {
- mLoader.resetImageForPreset(mPreset, null);
- }
if (force || mGeometryOnlyPreset == null) {
ImagePreset newPreset = new ImagePreset(mPreset);
newPreset.setDoApplyFilters(false);
if (mGeometryOnlyPreset == null
|| !newPreset.same(mGeometryOnlyPreset)) {
mGeometryOnlyPreset = newPreset;
- mGeometryOnlyImage = null;
}
}
if (force || mFiltersOnlyPreset == null) {
@@ -170,7 +205,6 @@ public class MasterImage {
if (mFiltersOnlyPreset == null
|| !newPreset.same(mFiltersOnlyPreset)) {
mFiltersOnlyPreset = newPreset;
- mFiltersOnlyImage = null;
}
}
mActivity.enableSave(hasModifications());
@@ -181,25 +215,9 @@ public class MasterImage {
return;
}
- Bitmap bitmap = mLoader.getImageForPreset(null, mPreset, true);
-
- if (bitmap != null) {
- mFilteredImage = bitmap;
- }
updatePresets(false);
- if (mGeometryOnlyPreset != null) {
- bitmap = mLoader.getImageForPreset(null, mGeometryOnlyPreset,
- true);
- if (bitmap != null) {
- mGeometryOnlyImage = bitmap;
- }
- }
- if (mFiltersOnlyPreset != null) {
- bitmap = mLoader.getImageForPreset(null, mFiltersOnlyPreset,
- true);
- if (bitmap != null) {
- mFiltersOnlyImage = bitmap;
- }
- }
+ FilteringPipeline.getPipeline().updatePreviewBuffer();
+ FilteringPipeline.getPipeline().updateGeometryOnlyPreviewBuffer();
+ FilteringPipeline.getPipeline().updateFiltersOnlyPreviewBuffer();
}
}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
index 8f3938406..b571ec6ae 100644
--- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
@@ -96,6 +96,14 @@ public class ImagePreset {
mDoApplyFilters = value;
}
+ public boolean getDoApplyFilters() {
+ return mDoApplyFilters;
+ }
+
+ public GeometryMetadata getGeometry() {
+ return mGeoData;
+ }
+
public boolean hasModifications() {
if (mImageBorder != null && !mImageBorder.isNil()) {
return true;
@@ -165,10 +173,31 @@ public class ImagePreset {
this.mImageLoader = mImageLoader;
}
+ public boolean equals(ImagePreset preset) {
+ if (!same(preset)) {
+ return false;
+ }
+ if (mDoApplyFilters && preset.mDoApplyFilters) {
+ for (int i = 0; i < preset.mFilters.size(); i++) {
+ ImageFilter a = preset.mFilters.elementAt(i);
+ ImageFilter b = mFilters.elementAt(i);
+ if (!a.equals(b)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
public boolean same(ImagePreset preset) {
+ if (preset == null) {
+ return false;
+ }
+
if (preset.mFilters.size() != mFilters.size()) {
return false;
}
+
if (!mName.equalsIgnoreCase(preset.name())) {
return false;
}
@@ -207,6 +236,32 @@ public class ImagePreset {
return true;
}
+ public int nbFilters() {
+ return mFilters.size();
+ }
+
+ public int similarUpTo(ImagePreset preset) {
+ if (!mGeoData.equals(preset.mGeoData)) {
+ return -1;
+ }
+
+ for (int i = 0; i < preset.mFilters.size(); i++) {
+ ImageFilter a = preset.mFilters.elementAt(i);
+ if (i < mFilters.size()) {
+ ImageFilter b = mFilters.elementAt(i);
+ if (!a.same(b)) {
+ return i;
+ }
+ if (a.getParameter() != b.getParameter()) {
+ return i;
+ }
+ } else {
+ return i;
+ }
+ }
+ return preset.mFilters.size();
+ }
+
public String name() {
return mName;
}
@@ -278,24 +333,40 @@ public class ImagePreset {
}
public Bitmap apply(Bitmap original) {
- // First we apply any transform -- 90 rotate, flip, straighten, crop
Bitmap bitmap = original;
+// bitmap = applyGeometry(bitmap);
+ bitmap = applyFilters(bitmap, -1, -1);
+ return applyBorder(bitmap);
+ }
+
+ public Bitmap applyGeometry(Bitmap bitmap) {
+ // Apply any transform -- 90 rotate, flip, straighten, crop
+ // Returns a new bitmap.
+ return mGeoData.apply(bitmap, mScaleFactor, mIsHighQuality);
+ }
- if (mDoApplyGeometry) {
- bitmap = mGeoData.apply(original, mScaleFactor, mIsHighQuality);
+ public Bitmap applyBorder(Bitmap bitmap) {
+ if (mImageBorder != null && mDoApplyGeometry) {
+ bitmap = mImageBorder.apply(bitmap, mScaleFactor, mIsHighQuality);
}
+ return bitmap;
+ }
+
+ public Bitmap applyFilters(Bitmap bitmap, int from, int to) {
if (mDoApplyFilters) {
- for (int i = 0; i < mFilters.size(); i++) {
+ if (from < 0) {
+ from = 0;
+ }
+ if (to == -1) {
+ to = mFilters.size();
+ }
+ for (int i = from; i < to; i++) {
ImageFilter filter = mFilters.elementAt(i);
bitmap = filter.apply(bitmap, mScaleFactor, mIsHighQuality);
}
}
- if (mImageBorder != null && mDoApplyGeometry) {
- bitmap = mImageBorder.apply(bitmap, mScaleFactor, mIsHighQuality);
- }
-
return bitmap;
}