diff options
author | nicolasroard <nicolasroard@google.com> | 2013-08-23 00:10:01 -0700 |
---|---|---|
committer | nicolasroard <nicolasroard@google.com> | 2013-08-27 00:47:43 -0700 |
commit | 9f452e09889199a28a86d9bd8f8fdaa8508ca0c1 (patch) | |
tree | d2dc35313a9467fc23e7db308da67be07985aba9 /src/com/android/gallery3d/filtershow | |
parent | 0594bd40959aaa55ec4f4204fbe3d12240f51480 (diff) | |
download | android_packages_apps_Gallery2-9f452e09889199a28a86d9bd8f8fdaa8508ca0c1.tar.gz android_packages_apps_Gallery2-9f452e09889199a28a86d9bd8f8fdaa8508ca0c1.tar.bz2 android_packages_apps_Gallery2-9f452e09889199a28a86d9bd8f8fdaa8508ca0c1.zip |
Improves UI / size
- improves overdraw
- filter change anim
- better borders
- remove unused images
bug:9470514
bug:8658176
Change-Id: I764879be415acbfba5a36f239d1905ec54e2d3cb
Diffstat (limited to 'src/com/android/gallery3d/filtershow')
16 files changed, 512 insertions, 69 deletions
diff --git a/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java b/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java index 95abce114..95fc56d4f 100644 --- a/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java +++ b/src/com/android/gallery3d/filtershow/EditorPlaceHolder.java @@ -45,7 +45,7 @@ public class EditorPlaceHolder { } editor.createEditor(mActivity, mContainer); - editor.getImageShow().bindAsImageLoadListener(); + editor.getImageShow().attach(); mContainer.setVisibility(View.VISIBLE); mContainer.removeAllViews(); View eview = editor.getTopLevelView(); diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index c3a5e15ff..c7e9cc68d 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -32,6 +32,7 @@ import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; @@ -66,6 +67,7 @@ import com.android.gallery3d.data.LocalAlbum; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.category.Action; import com.android.gallery3d.filtershow.category.CategoryAdapter; +import com.android.gallery3d.filtershow.category.CategorySelected; import com.android.gallery3d.filtershow.category.CategoryView; import com.android.gallery3d.filtershow.category.MainPanel; import com.android.gallery3d.filtershow.category.SwipableView; @@ -136,6 +138,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private View mSaveButton = null; private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this); + private Editor mCurrentEditor = null; private static final int SELECT_PICTURE = 1; private static final String LOGTAG = "FilterShowActivity"; @@ -364,6 +367,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL ActionBar actionBar = getActionBar(); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); actionBar.setCustomView(R.layout.filtershow_actionbar); + actionBar.setBackgroundDrawable(new ColorDrawable( + getResources().getColor(R.color.background_screen))); mSaveButton = actionBar.getCustomView(); mSaveButton.setOnClickListener(new OnClickListener() { @@ -600,6 +605,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) { return; } + if (filterRepresentation instanceof FilterUserPresetRepresentation + || filterRepresentation instanceof FilterRotateRepresentation + || filterRepresentation instanceof FilterMirrorRepresentation) { + MasterImage.getImage().onNewLook(filterRepresentation); + } ImagePreset oldPreset = MasterImage.getImage().getPreset(); ImagePreset copy = new ImagePreset(oldPreset); FilterRepresentation representation = copy.getRepresentation(filterRepresentation); @@ -639,7 +649,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL useFilterRepresentation(representation); // show representation - Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId()); + if (mCurrentEditor != null) { + mCurrentEditor.detach(); + } + mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId()); loadEditorPanel(representation, mCurrentEditor); hideInformationPanel(); } @@ -1358,4 +1371,27 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } return super.dispatchTouchEvent(ev); } + + public void startTouchAnimation(View target, float x, float y) { + final CategorySelected hint = + (CategorySelected) findViewById(R.id.categorySelectedIndicator); + int location[] = new int[2]; + target.getLocationOnScreen(location); + int locationHint[] = new int[2]; + ((View)hint.getParent()).getLocationOnScreen(locationHint); + int dx = (int) (x - (hint.getWidth())/2); + int dy = (int) (y - (hint.getHeight())/2); + hint.setTranslationX(location[0] - locationHint[0] + dx); + hint.setTranslationY(location[1] - locationHint[1] + dy); + hint.setVisibility(View.VISIBLE); + hint.animate().scaleX(2).scaleY(2).alpha(0).withEndAction(new Runnable() { + @Override + public void run() { + hint.setVisibility(View.INVISIBLE); + hint.setScaleX(1); + hint.setScaleY(1); + hint.setAlpha(1); + } + }); + } } diff --git a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java index 26998783d..339ddf07d 100644 --- a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java +++ b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java @@ -75,7 +75,7 @@ public class BitmapCache { public synchronized Bitmap getBitmap(int w, int h) { Long key = calcKey(w, h); - WeakReference<Bitmap> ref = null; //mBitmapCache.remove(key); + WeakReference<Bitmap> ref = null; ArrayList<WeakReference<Bitmap>> list = mBitmapCache.get(key); if (list != null && list.size() > 0) { ref = list.remove(0); diff --git a/src/com/android/gallery3d/filtershow/category/CategorySelected.java b/src/com/android/gallery3d/filtershow/category/CategorySelected.java new file mode 100644 index 000000000..1a6135bb8 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/category/CategorySelected.java @@ -0,0 +1,27 @@ +package com.android.gallery3d.filtershow.category; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.View; + +public class CategorySelected extends View { + Paint mPaint = new Paint(); + + public CategorySelected(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void onDraw(Canvas canvas) { + mPaint.reset(); + int margin = 20; + mPaint.setStrokeWidth(margin); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(Color.GRAY); + canvas.drawCircle(getWidth()/2, getHeight()/2, getWidth()/2 - margin, mPaint); + } + +} diff --git a/src/com/android/gallery3d/filtershow/category/CategoryView.java b/src/com/android/gallery3d/filtershow/category/CategoryView.java index 3a9d47355..c613c2174 100644 --- a/src/com/android/gallery3d/filtershow/category/CategoryView.java +++ b/src/com/android/gallery3d/filtershow/category/CategoryView.java @@ -154,6 +154,11 @@ public class CategoryView extends IconView @Override public boolean onTouchEvent(MotionEvent event) { boolean ret = super.onTouchEvent(event); + FilterShowActivity activity = (FilterShowActivity) getContext(); + + if (event.getActionMasked() == MotionEvent.ACTION_UP) { + activity.startTouchAnimation(this, event.getX(), event.getY()); + } if (!canBeRemoved()) { return ret; } @@ -171,7 +176,6 @@ public class CategoryView extends IconView delta = event.getX() - mStartTouchX; } if (Math.abs(delta) > mDeleteSlope) { - FilterShowActivity activity = (FilterShowActivity) getContext(); activity.setHandlesSwipeForView(this, mStartTouchX, mStartTouchY); } } diff --git a/src/com/android/gallery3d/filtershow/editors/Editor.java b/src/com/android/gallery3d/filtershow/editors/Editor.java index fb04fb35c..5f8e8f6f6 100644 --- a/src/com/android/gallery3d/filtershow/editors/Editor.java +++ b/src/com/android/gallery3d/filtershow/editors/Editor.java @@ -323,5 +323,8 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis } public void detach() { + if (mImageShow != null) { + mImageShow.detach(); + } } } diff --git a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java index 765796ea5..84caa9e75 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java @@ -23,8 +23,12 @@ import android.util.Log; import com.android.gallery3d.R; import com.android.gallery3d.filtershow.editors.EditorMirror; import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; +import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; import java.io.IOException; +import java.util.ArrayList; public class FilterMirrorRepresentation extends FilterRepresentation { public static final String SERIALIZATION_NAME = "MIRROR"; @@ -108,18 +112,34 @@ public class FilterMirrorRepresentation extends FilterRepresentation { mMirror = mirror; } + public boolean isHorizontal() { + if (mMirror == Mirror.BOTH + || mMirror == Mirror.HORIZONTAL) { + return true; + } + return false; + } + + public boolean isVertical() { + if (mMirror == Mirror.BOTH + || mMirror == Mirror.VERTICAL) { + return true; + } + return false; + } + public void cycle() { switch (mMirror) { case NONE: mMirror = Mirror.HORIZONTAL; break; case HORIZONTAL: - mMirror = Mirror.VERTICAL; - break; - case VERTICAL: mMirror = Mirror.BOTH; break; case BOTH: + mMirror = Mirror.VERTICAL; + break; + case VERTICAL: mMirror = Mirror.NONE; break; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java index 1cefe085e..e3cd56db7 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java +++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java @@ -23,6 +23,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; @@ -209,7 +210,19 @@ public final class GeometryMathUtils { return q; } - private static void concatMirrorMatrix(Matrix m, Mirror type) { + private static void concatMirrorMatrix(Matrix m, GeometryHolder holder) { + Mirror type = holder.mirror; + if (type == Mirror.HORIZONTAL) { + if (holder.rotation.value() == 90 + || holder.rotation.value() == 270) { + type = Mirror.VERTICAL; + } + } else if (type == Mirror.VERTICAL) { + if (holder.rotation.value() == 90 + || holder.rotation.value() == 270) { + type = Mirror.HORIZONTAL; + } + } if (type == Mirror.HORIZONTAL) { m.postScale(-1, 1); } else if (type == Mirror.VERTICAL) { @@ -299,7 +312,8 @@ public final class GeometryMathUtils { crop.roundOut(frame); Matrix m = getCropSelectionToScreenMatrix(null, holder, width, height, frame.width(), frame.height()); - Bitmap temp = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888); + BitmapCache bitmapCache = MasterImage.getImage().getBitmapCache(); + Bitmap temp = bitmapCache.getBitmap(frame.width(), frame.height()); Canvas canvas = new Canvas(temp); Paint paint = new Paint(); paint.setAntiAlias(true); @@ -345,7 +359,7 @@ public final class GeometryMathUtils { compensation.postRotate(angle, cx, cy); compensation.postRotate(rotation, cx, cy); compensation.postTranslate(-cx, -cy); - concatMirrorMatrix(compensation, holder.mirror); + concatMirrorMatrix(compensation, holder); compensation.postTranslate(cx, cy); return compensation; } @@ -371,6 +385,10 @@ public final class GeometryMathUtils { // If there are geometry changes, apply them to the image if (!holder.isNil()) { bmap = applyFullGeometryMatrix(bmap, holder); + if (bmap != image) { + BitmapCache cache = MasterImage.getImage().getBitmapCache(); + cache.cache(image); + } } return bmap; } @@ -410,7 +428,7 @@ public final class GeometryMathUtils { Matrix m = new Matrix(); m.setTranslate(-centerX, -centerY); m.postRotate(holder.straighten + holder.rotation.value()); - concatMirrorMatrix(m, holder.mirror); + concatMirrorMatrix(m, holder); return m; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java index 2bb269e29..ad4568723 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java @@ -19,13 +19,15 @@ package com.android.gallery3d.filtershow.imageshow; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.drawable.NinePatchDrawable; import android.util.AttributeSet; import android.view.GestureDetector; @@ -38,12 +40,14 @@ import android.widget.LinearLayout; import com.android.gallery3d.R; import com.android.gallery3d.filtershow.FilterShowActivity; +import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.ImageFilter; import com.android.gallery3d.filtershow.pipeline.ImagePreset; import com.android.gallery3d.filtershow.tools.SaveImage; import java.io.File; +import java.util.ArrayList; import java.util.Collection; public class ImageShow extends View implements OnGestureListener, @@ -74,6 +78,7 @@ public class ImageShow extends View implements OnGestureListener, private NinePatchDrawable mShadow = null; private Rect mShadowBounds = new Rect(); private int mShadowMargin = 15; // not scaled, fixed in the asset + private boolean mShadowDrawn = false; private Point mTouchDown = new Point(); private Point mTouch = new Point(); @@ -93,6 +98,21 @@ public class ImageShow extends View implements OnGestureListener, } InteractionMode mInteractionMode = InteractionMode.NONE; + private static Bitmap sMask; + private Paint mMaskPaint = new Paint(); + private Matrix mShaderMatrix = new Matrix(); + + private static Bitmap convertToAlphaMask(Bitmap b) { + Bitmap a = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ALPHA_8); + Canvas c = new Canvas(a); + c.drawBitmap(b, 0.0f, 0.0f, null); + return a; + } + + private static Shader createShader(Bitmap b) { + return new BitmapShader(b, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + } + private FilterShowActivity mActivity = null; public FilterShowActivity getActivity() { @@ -138,7 +158,20 @@ public class ImageShow extends View implements OnGestureListener, mShadow = (NinePatchDrawable) res.getDrawable(R.drawable.geometry_shadow); setupGestureDetector(context); mActivity = (FilterShowActivity) context; + if (sMask == null) { + Bitmap mask = BitmapFactory.decodeResource(res, R.drawable.spot_mask); + sMask = convertToAlphaMask(mask); + } + } + + public void attach() { MasterImage.getImage().addObserver(this); + bindAsImageLoadListener(); + } + + public void detach() { + MasterImage.getImage().removeObserver(this); + mMaskPaint.reset(); } public void setupGestureDetector(Context context) { @@ -206,36 +239,27 @@ public class ImageShow extends View implements OnGestureListener, float scaleFactor = MasterImage.getImage().getScaleFactor(); Point translation = MasterImage.getImage().getTranslation(); - Matrix scalingMatrix = new Matrix(); - scalingMatrix.postScale(scaleFactor, scaleFactor, cx, cy); - scalingMatrix.preTranslate(translation.x, translation.y); - - RectF unscaledClipRect = new RectF(mImageBounds); - scalingMatrix.mapRect(unscaledClipRect, unscaledClipRect); - canvas.save(); - boolean enablePartialRendering = false; - - // For now, partial rendering is disabled for all filters, - // so no need to clip. - if (enablePartialRendering && !unscaledClipRect.isEmpty()) { - canvas.clipRect(unscaledClipRect); - } + mShadowDrawn = false; canvas.save(); // TODO: center scale on gesture canvas.scale(scaleFactor, scaleFactor, cx, cy); canvas.translate(translation.x, translation.y); - drawImage(canvas, getFilteredImage(), true); Bitmap highresPreview = MasterImage.getImage().getHighresImage(); - if (highresPreview != null) { + + boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation(); + + if (!isDoingNewLookAnimation && highresPreview != null) { drawImage(canvas, highresPreview, true); + } else { + drawImage(canvas, getFilteredImage(), true); } canvas.restore(); Bitmap partialPreview = MasterImage.getImage().getPartialImage(); - if (partialPreview != null) { + if (!isDoingNewLookAnimation && partialPreview != null) { canvas.save(); Rect originalBounds = MasterImage.getImage().getOriginalBounds(); Collection<FilterRepresentation> geo = MasterImage.getImage().getPreset() @@ -274,30 +298,135 @@ public class ImageShow extends View implements OnGestureListener, } public void drawImage(Canvas canvas, Bitmap image, boolean updateBounds) { - if (image != null) { - Rect s = new Rect(0, 0, image.getWidth(), - image.getHeight()); - - float scale = GeometryMathUtils.scale(image.getWidth(), image.getHeight(), getWidth(), - getHeight()); - - float w = image.getWidth() * scale; - float h = image.getHeight() * scale; - float ty = (getHeight() - h) / 2.0f; - float tx = (getWidth() - w) / 2.0f; - - Rect d = new Rect((int) tx + mShadowMargin, - (int) ty + mShadowMargin, - (int) (w + tx) - mShadowMargin, - (int) (h + ty) - mShadowMargin); - if (updateBounds) { - mImageBounds = d; + if (image == null) { + return; + } + + Rect d = computeImageBounds(image); + + if (updateBounds) { + mImageBounds = d; + } + + float centerX = mShadowMargin + (getWidth() - 2 * mShadowMargin) / 2; + float centerY = mShadowMargin + (getHeight() - 2 * mShadowMargin) / 2; + + MasterImage master = MasterImage.getImage(); + canvas.save(); + if (master.onGoingNewLookAnimation()) { + if (master.getCurrentLookAnimation() + == MasterImage.CIRCLE_ANIMATION + && MasterImage.getImage().getPreviousImage() != null) { + float maskScale = MasterImage.getImage().getMaskScale(); + if (maskScale > 1.0f) { + float maskW = sMask.getWidth() / 2.0f; + float maskH = sMask.getHeight() / 2.0f; + float x = centerX - maskW * maskScale; + float y = centerY - maskH * maskScale; + + // Prepare the shader + mShaderMatrix.reset(); + mShaderMatrix.setScale(1.0f / maskScale, 1.0f / maskScale); + mShaderMatrix.preTranslate(-x + d.left, -y + d.top); + float scaleImageX = d.width() / (float) image.getWidth(); + float scaleImageY = d.height() / (float) image.getHeight(); + mShaderMatrix.preScale(scaleImageX, scaleImageY); + mMaskPaint.reset(); + mMaskPaint.setShader(createShader(image)); + mMaskPaint.getShader().setLocalMatrix(mShaderMatrix); + + drawImage(canvas, MasterImage.getImage().getPreviousImage()); + canvas.translate(x, y); + canvas.scale(maskScale, maskScale); + canvas.drawBitmap(sMask, 0, 0, mMaskPaint); + } else { + drawImage(canvas, image); + } + } else if (master.getCurrentLookAnimation() + == MasterImage.ROTATE_ANIMATION) { + Rect d2 = computeImageBounds(master.getPreviousImage()); + float finalScale = d.width() / (float) d2.height(); + finalScale = (1.0f * (1.0f - master.getAnimFraction())) + + (finalScale * master.getAnimFraction()); + canvas.rotate(master.getAnimRotationValue(), centerX, centerY); + canvas.scale(finalScale, finalScale, centerX, centerY); + drawImage(canvas, master.getPreviousImage()); + } else if (master.getCurrentLookAnimation() + == MasterImage.MIRROR_ANIMATION) { + if (master.getCurrentFilterRepresentation() + instanceof FilterMirrorRepresentation) { + FilterMirrorRepresentation rep = + (FilterMirrorRepresentation) master.getCurrentFilterRepresentation(); + + ImagePreset preset = master.getPreset(); + ArrayList<FilterRepresentation> geometry = + (ArrayList<FilterRepresentation>) preset.getGeometryFilters(); + GeometryMathUtils.GeometryHolder holder = null; + holder = GeometryMathUtils.unpackGeometry(geometry); + + if (holder.rotation.value() == 90 || holder.rotation.value() == 270) { + if (rep.isHorizontal() && !rep.isVertical()) { + canvas.scale(1, master.getAnimRotationValue(), centerX, centerY); + } else if (rep.isVertical() && !rep.isHorizontal()) { + canvas.scale(1, master.getAnimRotationValue(), centerX, centerY); + } else if (rep.isHorizontal() && rep.isVertical()) { + canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY); + } else { + canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY); + } + } else { + if (rep.isHorizontal() && !rep.isVertical()) { + canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY); + } else if (rep.isVertical() && !rep.isHorizontal()) { + canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY); + } else if (rep.isHorizontal() && rep.isVertical()) { + canvas.scale(1, master.getAnimRotationValue(), centerX, centerY); + } else { + canvas.scale(1, master.getAnimRotationValue(), centerX, centerY); + } + } + } + drawImage(canvas, master.getPreviousImage()); } + } else { + drawImage(canvas, image); + } + canvas.restore(); + } + + private void drawImage(Canvas canvas, Bitmap image) { + Rect d = computeImageBounds(image); + float scaleImageX = d.width() / (float) image.getWidth(); + float scaleImageY = d.height() / (float) image.getHeight(); + Matrix imageMatrix = new Matrix(); + imageMatrix.postScale(scaleImageX, scaleImageY); + imageMatrix.postTranslate(d.left, d.top); + drawShadow(canvas, d); + canvas.clipRect(d); + canvas.drawBitmap(image, imageMatrix, mPaint); + } + + private Rect computeImageBounds(Bitmap image) { + float scale = GeometryMathUtils.scale(image.getWidth(), image.getHeight(), + getWidth(), getHeight()); + + float w = image.getWidth() * scale; + float h = image.getHeight() * scale; + float ty = (getHeight() - h) / 2.0f; + float tx = (getWidth() - w) / 2.0f; + return new Rect((int) tx + mShadowMargin, + (int) ty + mShadowMargin, + (int) (w + tx) - mShadowMargin, + (int) (h + ty) - mShadowMargin); + } + + private void drawShadow(Canvas canvas, Rect d) { + if (!mShadowDrawn) { mShadowBounds.set(d.left - mShadowMargin, d.top - mShadowMargin, d.right + mShadowMargin, d.bottom + mShadowMargin); mShadow.setBounds(mShadowBounds); mShadow.draw(canvas); - canvas.drawBitmap(image, s, d, mPaint); + mShadowDrawn = true; } } diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java index fabc7b3dc..525b45801 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java +++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java @@ -16,6 +16,8 @@ package com.android.gallery3d.filtershow.imageshow; +import android.animation.Animator; +import android.animation.ValueAnimator; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Point; @@ -24,12 +26,16 @@ import android.graphics.RectF; import android.net.Uri; import android.os.Handler; import android.os.Message; +import android.util.Log; import com.android.gallery3d.exif.ExifTag; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation; +import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; import com.android.gallery3d.filtershow.filters.ImageFilter; import com.android.gallery3d.filtershow.history.HistoryItem; import com.android.gallery3d.filtershow.history.HistoryManager; @@ -77,6 +83,16 @@ public class MasterImage implements RenderingRequestCaller { private Bitmap mFiltersOnlyBitmap = null; private Bitmap mPartialBitmap = null; private Bitmap mHighresBitmap = null; + private Bitmap mPreviousImage = null; + + private float mMaskScale = 1; + private boolean mOnGoingNewLookAnimation = false; + private float mAnimRotationValue = 0; + private float mAnimFraction = 0; + private int mCurrentLookAnimation = 0; + public static final int CIRCLE_ANIMATION = 1; + public static final int ROTATE_ANIMATION = 2; + public static final int MIRROR_ANIMATION = 3; private HistoryManager mHistory = null; private StateAdapter mState = null; @@ -205,6 +221,10 @@ public class MasterImage implements RenderingRequestCaller { mObservers.add(observer); } + public void removeObserver(ImageShow observer) { + mObservers.remove(observer); + } + public void setActivity(FilterShowActivity activity) { mActivity = activity; } @@ -328,6 +348,103 @@ public class MasterImage implements RenderingRequestCaller { return mHighresBitmap; } + public Bitmap getPreviousImage() { + return mPreviousImage; + } + + public float getMaskScale() { + return mMaskScale; + } + + public void setMaskScale(float scale) { + mMaskScale = scale; + notifyObservers(); + } + + public float getAnimRotationValue() { + return mAnimRotationValue; + } + + public void setAnimRotation(float rotation) { + mAnimRotationValue = rotation; + notifyObservers(); + } + + public void setAnimFraction(float fraction) { + mAnimFraction = fraction; + } + + public float getAnimFraction() { + return mAnimFraction; + } + + public boolean onGoingNewLookAnimation() { + return mOnGoingNewLookAnimation; + } + + public int getCurrentLookAnimation() { + return mCurrentLookAnimation; + } + + public void onNewLook(FilterRepresentation newRepresentation) { + getBitmapCache().cache(mPreviousImage); + mPreviousImage = getBitmapCache().getBitmapCopy(getFilteredImage()); + ValueAnimator animator = null; + if (newRepresentation instanceof FilterUserPresetRepresentation) { + mCurrentLookAnimation = CIRCLE_ANIMATION; + animator = ValueAnimator.ofFloat(1, 20); + } + if (newRepresentation instanceof FilterRotateRepresentation) { + mCurrentLookAnimation = ROTATE_ANIMATION; + animator = ValueAnimator.ofFloat(0, 90); + } + if (newRepresentation instanceof FilterMirrorRepresentation) { + mCurrentLookAnimation = MIRROR_ANIMATION; + animator = ValueAnimator.ofFloat(1, 0, -1); + } + animator.setDuration(400); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + if (mCurrentLookAnimation == CIRCLE_ANIMATION) { + Log.v(LOGTAG, "circle animation " + animation.getAnimatedValue()); + setMaskScale((Float) animation.getAnimatedValue()); + } else if (mCurrentLookAnimation == ROTATE_ANIMATION + || mCurrentLookAnimation == MIRROR_ANIMATION) { + setAnimRotation((Float) animation.getAnimatedValue()); + setAnimFraction(animation.getAnimatedFraction()); + } + } + }); + animator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + mOnGoingNewLookAnimation = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + mBitmapCache.cache(mPreviousImage); + mPreviousImage = null; + mOnGoingNewLookAnimation = false; + setMaskScale(1); + setAnimRotation(0); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + animator.start(); + notifyObservers(); + } + public void notifyObservers() { for (ImageShow observer : mObservers) { observer.invalidate(); @@ -339,9 +456,9 @@ public class MasterImage implements RenderingRequestCaller { newPresetGeometryOnly.setDoApplyFilters(false); newPresetGeometryOnly.setDoApplyGeometry(true); if (force || mGeometryOnlyPreset == null - || !newPresetGeometryOnly.same(mGeometryOnlyPreset)) { + || !newPresetGeometryOnly.equals(mGeometryOnlyPreset)) { mGeometryOnlyPreset = newPresetGeometryOnly; - RenderingRequest.post(mActivity, getOriginalBitmapLarge(), + RenderingRequest.post(mActivity, null, mGeometryOnlyPreset, RenderingRequest.GEOMETRY_RENDERING, this); } ImagePreset newPresetFiltersOnly = new ImagePreset(mPreset); @@ -350,7 +467,7 @@ public class MasterImage implements RenderingRequestCaller { if (force || mFiltersOnlyPreset == null || !newPresetFiltersOnly.same(mFiltersOnlyPreset)) { mFiltersOnlyPreset = newPresetFiltersOnly; - RenderingRequest.post(mActivity, MasterImage.getImage().getOriginalBitmapLarge(), + RenderingRequest.post(mActivity, null, mFiltersOnlyPreset, RenderingRequest.FILTERS_RENDERING, this); } } @@ -474,10 +591,12 @@ public class MasterImage implements RenderingRequestCaller { boolean needsCheckModification = false; if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) { + mBitmapCache.cache(mGeometryOnlyBitmap); mGeometryOnlyBitmap = request.getBitmap(); needsCheckModification = true; } if (request.getType() == RenderingRequest.FILTERS_RENDERING) { + mBitmapCache.cache(mFiltersOnlyBitmap); mFiltersOnlyBitmap = request.getBitmap(); notifyObservers(); needsCheckModification = true; diff --git a/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java index 8f6eda261..2a8321908 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java +++ b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java @@ -170,9 +170,11 @@ public class CacheProcessing { + mSteps.size() + " cacheBitmap: " + cacheBitmap); } + Bitmap originalCopy = null; for (int i = findBaseImageIndex; i < mSteps.size(); i++) { if (i == -1 || cacheBitmap == null) { cacheBitmap = environment.getBitmapCopy(originalBitmap); + originalCopy = cacheBitmap; if (DEBUG) { Log.v(LOGTAG, "i: " + i + " cacheBitmap: " + cacheBitmap + " w: " + cacheBitmap.getWidth() + " h: " + cacheBitmap.getHeight() @@ -189,12 +191,12 @@ public class CacheProcessing { Log.v(LOGTAG, "i: " + i + " get new copy for cacheBitmap " + cacheBitmap + " apply..."); } - environment.cache(step.cache); cacheBitmap = environment.getBitmapCopy(cacheBitmap); cacheBitmap = step.apply(environment, cacheBitmap); step.cache = cacheBitmap; } } + environment.cache(originalCopy); if (DEBUG) { Log.v(LOGTAG, "now let's cleanup the cache..."); diff --git a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java index 0ff8bfbad..823da642a 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java +++ b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java @@ -221,18 +221,64 @@ public class CachingPipeline implements PipelineInterface { Bitmap bmp = preset.apply(bitmap, mEnvironment); if (!mEnvironment.needsStop()) { request.setBitmap(bmp); + } else { + mEnvironment.cache(bmp); + } + mFiltersManager.freeFilterResources(preset); + } + } + + public void renderGeometry(RenderingRequest request) { + synchronized (CachingPipeline.class) { + if (getRenderScriptContext() == null) { + return; + } + ImagePreset preset = request.getImagePreset(); + setupEnvironment(preset, false); + Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres(); + if (bitmap == null) { + return; + } + bitmap = mEnvironment.getBitmapCopy(bitmap); + bitmap = preset.applyGeometry(bitmap, mEnvironment); + if (!mEnvironment.needsStop()) { + request.setBitmap(bitmap); + } else { + mEnvironment.cache(bitmap); + } + mFiltersManager.freeFilterResources(preset); + } + } + + public void renderFilters(RenderingRequest request) { + synchronized (CachingPipeline.class) { + if (getRenderScriptContext() == null) { + return; + } + ImagePreset preset = request.getImagePreset(); + setupEnvironment(preset, false); + Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres(); + if (bitmap == null) { + return; + } + bitmap = mEnvironment.getBitmapCopy(bitmap); + bitmap = preset.apply(bitmap, mEnvironment); + if (!mEnvironment.needsStop()) { + request.setBitmap(bitmap); + } else { + mEnvironment.cache(bitmap); } mFiltersManager.freeFilterResources(preset); } } public synchronized void render(RenderingRequest request) { + // TODO: cleanup/remove GEOMETRY / FILTERS paths synchronized (CachingPipeline.class) { if (getRenderScriptContext() == null) { return; } - if (((request.getType() != RenderingRequest.PARTIAL_RENDERING - && request.getType() != RenderingRequest.HIGHRES_RENDERING) + if (((request.getType() != RenderingRequest.PARTIAL_RENDERING) && request.getBitmap() == null) || request.getImagePreset() == null) { return; @@ -244,8 +290,7 @@ public class CachingPipeline implements PipelineInterface { Bitmap bitmap = request.getBitmap(); ImagePreset preset = request.getImagePreset(); - setupEnvironment(preset, - request.getType() != RenderingRequest.HIGHRES_RENDERING); + setupEnvironment(preset, true); mFiltersManager.freeFilterResources(preset); if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { @@ -260,13 +305,6 @@ public class CachingPipeline implements PipelineInterface { } } - if (request.getType() == RenderingRequest.HIGHRES_RENDERING) { - bitmap = MasterImage.getImage().getOriginalBitmapHighres(); - if (bitmap != null) { - bitmap = preset.applyGeometry(bitmap, mEnvironment); - } - } - if (request.getType() == RenderingRequest.FULL_RENDERING || request.getType() == RenderingRequest.GEOMETRY_RENDERING || request.getType() == RenderingRequest.FILTERS_RENDERING) { @@ -290,7 +328,6 @@ public class CachingPipeline implements PipelineInterface { || request.getType() == RenderingRequest.FILTERS_RENDERING || request.getType() == RenderingRequest.ICON_RENDERING || request.getType() == RenderingRequest.PARTIAL_RENDERING - || request.getType() == RenderingRequest.HIGHRES_RENDERING || request.getType() == RenderingRequest.STYLE_ICON_RENDERING) { if (request.getType() == RenderingRequest.ICON_RENDERING) { @@ -351,6 +388,7 @@ public class CachingPipeline implements PipelineInterface { Vector<FilterRepresentation> filters = preset.getFilters(); Bitmap result = mCachedProcessing.process(mOriginalBitmap, filters, mEnvironment); buffer.setProducer(result); + mEnvironment.cache(result); } public synchronized void computeOld(SharedBuffer buffer, ImagePreset preset, int type) { diff --git a/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java b/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java index b34537668..72c02f32f 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java +++ b/src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java @@ -133,6 +133,9 @@ public class FilterEnvironment { filter.useRepresentation(representation); filter.setEnvironment(this); Bitmap ret = filter.apply(bitmap, mScaleFactor, mQuality); + if (bitmap != ret) { + cache(bitmap); + } filter.setGeneralParameters(); filter.setEnvironment(null); return ret; diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java index 88e8d42e8..3f71547dd 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java @@ -24,6 +24,7 @@ import android.util.JsonWriter; import android.util.Log; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.filters.BaseFiltersManager; import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; @@ -235,6 +236,37 @@ public class ImagePreset { return true; } + public boolean equals(ImagePreset preset) { + if (preset == null) { + return false; + } + + if (preset.mFilters.size() != mFilters.size()) { + return false; + } + + if (mDoApplyGeometry != preset.mDoApplyGeometry) { + return false; + } + + if (mDoApplyFilters != preset.mDoApplyFilters) { + if (mFilters.size() > 0 || preset.mFilters.size() > 0) { + return false; + } + } + + for (int i = 0; i < preset.mFilters.size(); i++) { + FilterRepresentation a = preset.mFilters.elementAt(i); + FilterRepresentation b = mFilters.elementAt(i); + + if (!a.equals(b)) { + return false; + } + } + + return true; + } + public int similarUpTo(ImagePreset preset) { for (int i = 0; i < preset.mFilters.size(); i++) { FilterRepresentation a = preset.mFilters.elementAt(i); @@ -476,7 +508,11 @@ public class ImagePreset { // TODO: might be worth getting rid of applyBorder. continue; } + Bitmap tmp = bitmap; bitmap = environment.applyRepresentation(representation, bitmap); + if (tmp != bitmap) { + environment.cache(tmp); + } if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, "SaveFilter", representation.getSerializationName(), 1); diff --git a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java index ef4bb9bc0..463b38d95 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java +++ b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java @@ -52,7 +52,8 @@ public class RenderingRequest { public static void post(Context context, Bitmap source, ImagePreset preset, int type, RenderingRequestCaller caller, Rect bounds, Rect destination) { - if (((type != PARTIAL_RENDERING && type != HIGHRES_RENDERING) && source == null) + if (((type != PARTIAL_RENDERING && type != HIGHRES_RENDERING + && type != GEOMETRY_RENDERING && type != FILTERS_RENDERING) && source == null) || preset == null || caller == null) { Log.v(LOGTAG, "something null: source: " + source + " or preset: " + preset + " or caller: " + caller); @@ -61,14 +62,15 @@ public class RenderingRequest { RenderingRequest request = new RenderingRequest(); Bitmap bitmap = null; if (type == FULL_RENDERING - || type == GEOMETRY_RENDERING || type == ICON_RENDERING || type == STYLE_ICON_RENDERING) { CachingPipeline pipeline = new CachingPipeline( FiltersManager.getManager(), "Icon"); bitmap = pipeline.renderGeometryIcon(source, preset); - } else if (type != PARTIAL_RENDERING && type != HIGHRES_RENDERING) { - bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), mConfig); + } else if (type != PARTIAL_RENDERING && type != HIGHRES_RENDERING + && type != GEOMETRY_RENDERING && type != FILTERS_RENDERING) { + bitmap = MasterImage.getImage().getBitmapCache().getBitmap( + source.getWidth(), source.getHeight()); } request.setBitmap(bitmap); diff --git a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequestTask.java b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequestTask.java index 7a83f7072..c8bc57d38 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequestTask.java +++ b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequestTask.java @@ -63,7 +63,13 @@ public class RenderingRequestTask extends ProcessingTask { public Result doInBackground(Request message) { RenderingRequest request = ((Render) message).request; RenderResult result = null; - mPreviewPipeline.render(request); + if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) { + mPreviewPipeline.renderGeometry(request); + } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) { + mPreviewPipeline.renderFilters(request); + } else { + mPreviewPipeline.render(request); + } result = new RenderResult(); result.request = request; return result; |