diff options
author | nicolasroard <nicolasroard@google.com> | 2012-10-02 21:57:22 -0700 |
---|---|---|
committer | nicolasroard <nicolasroard@google.com> | 2012-10-04 17:11:52 -0700 |
commit | 5448bf8095483574649afcc2add7f153670c7450 (patch) | |
tree | 13b3e7532f79cfcce29325914642389b9933e8cc | |
parent | 94805da05624e939ff402a9586cddacaf622a716 (diff) | |
download | android_packages_apps_Gallery2-5448bf8095483574649afcc2add7f153670c7450.tar.gz android_packages_apps_Gallery2-5448bf8095483574649afcc2add7f153670c7450.tar.bz2 android_packages_apps_Gallery2-5448bf8095483574649afcc2add7f153670c7450.zip |
Implement sharpen
bug:7279964
bug:7247494
bug:7234321
- add a sharpen filter
- add infrastructure to use RenderScript
- some refactoring (add an ImageSlave class)
- add new zoom UI
Change-Id: Id94dc94d32866c7107b6818adf4db35d0c6c0b01
17 files changed, 576 insertions, 100 deletions
diff --git a/Android.mk b/Android.mk index 1e4430bee..e2914bb3a 100644 --- a/Android.mk +++ b/Android.mk @@ -8,7 +8,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13 LOCAL_STATIC_JAVA_LIBRARIES += com.android.gallery3d.common2 LOCAL_STATIC_JAVA_LIBRARIES += mp4parser -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) LOCAL_SRC_FILES += $(call all-java-files-under, src_pd) LOCAL_SRC_FILES += $(call all-java-files-under, ../Camera/src) diff --git a/res/layout/filtershow_activity.xml b/res/layout/filtershow_activity.xml index 0dead607f..1449f16e9 100644 --- a/res/layout/filtershow_activity.xml +++ b/res/layout/filtershow_activity.xml @@ -125,6 +125,12 @@ android:layout_height="wrap_content" android:visibility="gone" /> + <com.android.gallery3d.filtershow.imageshow.ImageZoom + android:id="@+id/imageZoom" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone" /> + <ImageButton android:id="@+id/showOriginalButton" android:layout_width="64dip" diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index 694f51290..389973e50 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -11,6 +11,7 @@ import com.android.gallery3d.filtershow.imageshow.ImageBorder; import com.android.gallery3d.filtershow.imageshow.ImageShow; import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter; import com.android.gallery3d.filtershow.imageshow.ImageStraighten; +import com.android.gallery3d.filtershow.imageshow.ImageZoom; import com.android.gallery3d.filtershow.presets.*; import com.android.gallery3d.filtershow.provider.SharedImageProvider; import com.android.gallery3d.filtershow.tools.SaveCopyTask; @@ -19,6 +20,7 @@ import com.android.gallery3d.R; import android.net.Uri; import android.os.Bundle; +import android.renderscript.RenderScript; import android.annotation.TargetApi; import android.app.ActionBar; import android.app.Activity; @@ -57,6 +59,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, private ImageCurves mImageCurves = null; private ImageBorder mImageBorders = null; private ImageStraighten mImageStraighten = null; + private ImageZoom mImageZoom = null; private View mListFx = null; private View mListBorders = null; @@ -100,6 +103,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + ImageFilterRS.setRenderScriptContext(this); + setContentView(R.layout.filtershow_activity); ActionBar actionBar = getActionBar(); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); @@ -121,11 +126,13 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mImageCurves = (ImageCurves) findViewById(R.id.imageCurves); mImageBorders = (ImageBorder) findViewById(R.id.imageBorder); mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten); + mImageZoom = (ImageZoom) findViewById(R.id.imageZoom); mImageViews.add(mImageShow); mImageViews.add(mImageCurves); mImageViews.add(mImageBorders); mImageViews.add(mImageStraighten); + mImageViews.add(mImageZoom); mListFx = findViewById(R.id.fxList); mListBorders = findViewById(R.id.bordersList); @@ -211,6 +218,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mImageBorders.setMaster(mImageShow); mImageStraighten.setImageLoader(mImageLoader); mImageStraighten.setMaster(mImageShow); + mImageZoom.setImageLoader(mImageLoader); + mImageZoom.setMaster(mImageShow); Intent intent = getIntent(); String data = intent.getDataString(); @@ -688,11 +697,23 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, @Override public void onClick(View v) { hideImageViews(); - mImageShow.setVisibility(View.VISIBLE); + mImageZoom.setVisibility(View.VISIBLE); + mImageZoom.setShowControls(true); + ImagePreset preset = mImageZoom.getImagePreset(); + ImageFilter filter = preset.getFilter("Sharpen"); + if (filter == null) { + ImageFilterSharpen sharpen = new ImageFilterSharpen(); + ImagePreset copy = new ImagePreset(preset); + copy.add(sharpen); + copy.setHistoryName(sharpen.getName()); + copy.setIsFx(false); + filter = copy.getFilter("Sharpen"); + mImageZoom.setImagePreset(copy); + } + mImageZoom.setCurrentFilter(filter); unselectPanelButtons(mColorsPanelButtons); mSharpenButton.setSelected(true); - mImageShow.showToast("Sharpen", true); - mImageShow.setCurrentFilter(null); + invalidateViews(); } }; } diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java index ac16c13cd..9944f5fce 100644 --- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java +++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java @@ -8,7 +8,9 @@ import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.BitmapRegionDecoder; import android.graphics.Matrix; +import android.graphics.Rect; import android.media.ExifInterface; import android.net.Uri; import android.provider.MediaStore; @@ -42,6 +44,7 @@ public class ImageLoader { private Cache mCache = new DelayedPresetCache(30); private Cache mHiresCache = new DelayedPresetCache(2); + private ZoomCache mZoomCache = new ZoomCache(); private int mOrientation = 0; private HistoryAdapter mAdapter = null; @@ -50,6 +53,8 @@ public class ImageLoader { private Context mContext = null; private Uri mUri = null; + private Rect mOriginalBounds = null; + public ImageLoader(Context context) { mContext = context; } @@ -66,6 +71,10 @@ public class ImageLoader { return mUri; } + public Rect getOriginalBounds() { + return mOriginalBounds; + } + private int getOrientation(Uri uri) { if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { return getOrientationFromPath(uri.getPath()); @@ -125,6 +134,22 @@ public class ImageLoader { } } + private Bitmap loadRegionBitmap(Uri uri, Rect bounds) { + InputStream is = null; + try { + is = mContext.getContentResolver().openInputStream(uri); + BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false); + return decoder.decodeRegion(bounds, null); + } catch (FileNotFoundException e) { + Log.e(LOGTAG, "FileNotFoundException: " + uri); + } catch (Exception e) { + e.printStackTrace(); + } finally { + closeStream(is); + } + return null; + } + private Bitmap loadScaledBitmap(Uri uri, int size) { InputStream is = null; try { @@ -137,6 +162,9 @@ public class ImageLoader { int width_tmp = o.outWidth; int height_tmp = o.outHeight; + + mOriginalBounds = new Rect(0, 0, width_tmp, height_tmp); + int scale = 1; while (true) { if (width_tmp / 2 < size || height_tmp / 2 < size) @@ -192,6 +220,24 @@ public class ImageLoader { } } + // TODO: 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) { + Bitmap bmp = mZoomCache.getImage(imagePreset, bounds); + if (force || bmp == null) { + bmp = loadRegionBitmap(mUri, bounds); + if (bmp != null) { + // TODO: this workaround for RS might not be needed ultimately + Bitmap bmp2 = bmp.copy(Bitmap.Config.ARGB_8888, true); + imagePreset.apply(bmp2); + mZoomCache.setImage(imagePreset, bounds, bmp2); + return bmp2; + } + } + return bmp; + } + // Caching method public Bitmap getImageForPreset(ImageShow caller, ImagePreset imagePreset, boolean hiRes) { @@ -223,6 +269,7 @@ public class ImageLoader { public void resetImageForPreset(ImagePreset imagePreset, ImageShow caller) { mHiresCache.reset(imagePreset); mCache.reset(imagePreset); + mZoomCache.reset(imagePreset); } public Uri saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity, diff --git a/src/com/android/gallery3d/filtershow/cache/ZoomCache.java b/src/com/android/gallery3d/filtershow/cache/ZoomCache.java new file mode 100644 index 000000000..e6e7f14ce --- /dev/null +++ b/src/com/android/gallery3d/filtershow/cache/ZoomCache.java @@ -0,0 +1,39 @@ +package com.android.gallery3d.filtershow.cache; + +import android.graphics.Bitmap; +import android.graphics.Rect; + +import com.android.gallery3d.filtershow.presets.ImagePreset; + +public class ZoomCache { + + private ImagePreset mImagePreset = null; + private Bitmap mBitmap = null; + private Rect mBounds = null; + + // TODO: move the processing to a background thread... + public Bitmap getImage(ImagePreset preset, Rect bounds) { + if (mBounds != bounds) { + return null; + } + if (mImagePreset == null) { + return null; + } + if (!mImagePreset.same(preset)) { + return null; + } + return mBitmap; + } + + public void setImage(ImagePreset preset, Rect bounds, Bitmap bitmap) { + mBitmap = bitmap; + mBounds = bounds; + mImagePreset = preset; + } + + public void reset(ImagePreset imagePreset) { + if (imagePreset == mImagePreset) { + mBitmap = null; + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java index c2bd952f8..c039fce47 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java @@ -2,11 +2,13 @@ package com.android.gallery3d.filtershow.filters; import android.graphics.Bitmap; +import android.util.Log; public class ImageFilter implements Cloneable { protected int mParameter = 0; protected String mName = "Original"; + private final String LOGTAG = "ImageFilter"; @Override public ImageFilter clone() throws CloneNotSupportedException { diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java new file mode 100644 index 000000000..ab2d304a4 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java @@ -0,0 +1,59 @@ +package com.android.gallery3d.filtershow.filters; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.renderscript.Allocation; +import android.renderscript.RenderScript; +import android.util.Log; + +public class ImageFilterRS extends ImageFilter { + private final String LOGTAG = "ImageFilterRS"; + + private static RenderScript mRS = null; + protected static Allocation mInPixelsAllocation; + protected static Allocation mOutPixelsAllocation; + private static android.content.res.Resources mResources = null; + + public void prepare(Bitmap bitmap) { + 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) { + } + + public void runFilter() { + } + + public void update(Bitmap bitmap) { + mOutPixelsAllocation.copyTo(bitmap); + } + + public void apply(Bitmap bitmap) { + if (bitmap == null) { + return; + } + try { + prepare(bitmap); + createFilter(mResources); + runFilter(); + update(bitmap); + } catch (android.renderscript.RSIllegalArgumentException e) { + Log.e(LOGTAG, "Illegal argument? " + e); + } catch (android.renderscript.RSRuntimeException e) { + Log.e(LOGTAG, "RS runtime exception ? " + e); + } + } + + public static RenderScript getRenderScriptContext() { + return mRS; + } + + public static void setRenderScriptContext(Activity context) { + mRS = RenderScript.create(context); + mResources = context.getResources(); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java new file mode 100644 index 000000000..3ec7b5f70 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java @@ -0,0 +1,52 @@ + +package com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.util.Log; +import android.renderscript.Element; +import android.renderscript.Script; +import android.renderscript.ScriptC; + +import com.android.gallery3d.R; + +public class ImageFilterSharpen extends ImageFilterRS { + + private static final String LOGTAG = "ImageFilterSharpen"; + private ScriptC_convolve3x3 mScript; + + public ImageFilterSharpen() { + mName = "Sharpen"; + } + + public void createFilter(android.content.res.Resources res) { + int w = mInPixelsAllocation.getType().getX(); + int h = mInPixelsAllocation.getType().getY(); + + float p1 = mParameter; + float value = p1 / 100.0f; + float f[] = new float[9]; + float p = value; + f[0] = -p; + f[1] = -p; + f[2] = -p; + f[3] = -p; + f[4] = 8 * p + 1; + f[5] = -p; + f[6] = -p; + f[7] = -p; + f[8] = -p; + if (mScript == null) { + mScript = new ScriptC_convolve3x3(getRenderScriptContext(), res, R.raw.convolve3x3); + } + mScript.set_gCoeffs(f); + mScript.set_gWidth(w); + mScript.set_gHeight(h); + } + + public void runFilter() { + mScript.set_gIn(mInPixelsAllocation); + mScript.bind_gPixels(mInPixelsAllocation); + mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/convolve3x3.rs b/src/com/android/gallery3d/filtershow/filters/convolve3x3.rs new file mode 100644 index 000000000..2acffab06 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/convolve3x3.rs @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.gallery3d.filtershow.filters) +#pragma rs_fp_relaxed + +int32_t gWidth; +int32_t gHeight; +const uchar4 *gPixels; +rs_allocation gIn; + +float gCoeffs[9]; + +void root(const uchar4 *in, uchar4 *out, const void *usrData, uint32_t x, uint32_t y) { + uint32_t x1 = min((int32_t)x+1, gWidth-1); + uint32_t x2 = max((int32_t)x-1, 0); + uint32_t y1 = min((int32_t)y+1, gHeight-1); + uint32_t y2 = max((int32_t)y-1, 0); + + float4 p00 = rsUnpackColor8888(gPixels[x1 + gWidth * y1]); + float4 p01 = rsUnpackColor8888(gPixels[x + gWidth * y1]); + float4 p02 = rsUnpackColor8888(gPixels[x2 + gWidth * y1]); + float4 p10 = rsUnpackColor8888(gPixels[x1 + gWidth * y]); + float4 p11 = rsUnpackColor8888(gPixels[x + gWidth * y]); + float4 p12 = rsUnpackColor8888(gPixels[x2 + gWidth * y]); + float4 p20 = rsUnpackColor8888(gPixels[x1 + gWidth * y2]); + float4 p21 = rsUnpackColor8888(gPixels[x + gWidth * y2]); + float4 p22 = rsUnpackColor8888(gPixels[x2 + gWidth * y2]); + + p00 *= gCoeffs[0]; + p01 *= gCoeffs[1]; + p02 *= gCoeffs[2]; + p10 *= gCoeffs[3]; + p11 *= gCoeffs[4]; + p12 *= gCoeffs[5]; + p20 *= gCoeffs[6]; + p21 *= gCoeffs[7]; + p22 *= gCoeffs[8]; + + p00 += p01; + p02 += p10; + p11 += p12; + p20 += p21; + + p22 += p00; + p02 += p11; + + p20 += p22; + p20 += p02; + + p20 = clamp(p20, 0.f, 1.f); + *out = rsPackColorTo8888(p20.r, p20.g, p20.b); +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageBorder.java b/src/com/android/gallery3d/filtershow/imageshow/ImageBorder.java index 00be8267d..f8c0142ae 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageBorder.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageBorder.java @@ -13,9 +13,8 @@ import android.graphics.Rect; import android.graphics.drawable.NinePatchDrawable; import android.util.AttributeSet; -public class ImageBorder extends ImageShow { +public class ImageBorder extends ImageSlave { Paint gPaint = new Paint(); - private ImageShow mMasterImageShow = null; public ImageBorder(Context context) { super(context); @@ -25,18 +24,6 @@ public class ImageBorder extends ImageShow { super(context, attrs); } - public void setMaster(ImageShow master) { - mMasterImageShow = master; - } - - public ImagePreset getImagePreset() { - return mMasterImageShow.getImagePreset(); - } - - public void setImagePreset(ImagePreset preset, boolean addToHistory) { - mMasterImageShow.setImagePreset(preset, addToHistory); - } - public boolean showTitle() { return false; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java index 2caa2d578..2a660d40f 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java @@ -61,19 +61,31 @@ public class ImageShow extends View implements SliderListener { private boolean mShowToast = false; private boolean mImportantToast = false; + protected float mTouchX = 0; + protected float mTouchY = 0; + private Handler mHandler = new Handler(); public void onNewValue(int value) { - if (mCurrentFilter != null) { - mCurrentFilter.setParameter(value); + if (getCurrentFilter() != null) { + getCurrentFilter().setParameter(value); } - if (mImagePreset != null) { - mImageLoader.resetImageForPreset(mImagePreset, this); - mImagePreset.fillImageStateAdapter(mImageStateAdapter); + if (getImagePreset() != null) { + mImageLoader.resetImageForPreset(getImagePreset(), this); + getImagePreset().fillImageStateAdapter(mImageStateAdapter); } invalidate(); } + public void onTouchDown(float x, float y) { + mTouchX = x; + mTouchY = y; + invalidate(); + } + + public void onTouchUp() { + } + public ImageShow(Context context, AttributeSet attrs) { super(context, attrs); mSliderController.setListener(this); @@ -102,6 +114,10 @@ public class ImageShow extends View implements SliderListener { mCurrentFilter = filter; } + public ImageFilter getCurrentFilter() { + return mCurrentFilter; + } + public void setAdapter(HistoryAdapter adapter) { mHistoryAdapter = adapter; } @@ -125,6 +141,10 @@ public class ImageShow extends View implements SliderListener { }, 400); } + public Rect getImageBounds() { + return mImageBounds; + } + public ImagePreset getImagePreset() { return mImagePreset; } @@ -161,16 +181,32 @@ public class ImageShow extends View implements SliderListener { } public void onDraw(Canvas canvas) { - if (mBackgroundImage == null) { - mBackgroundImage = mImageLoader.getBackgroundBitmap(getResources()); + drawBackground(canvas); + getFilteredImage(); + drawImage(canvas, mFilteredImage); + + if (showTitle() && getImagePreset() != null) { + mPaint.setARGB(200, 0, 0, 0); + mPaint.setTextSize(mTextSize); + + Rect textRect = new Rect(0, 0, getWidth(), mTextSize + mTextPadding); + canvas.drawRect(textRect, mPaint); + mPaint.setARGB(255, 200, 200, 200); + canvas.drawText(getImagePreset().name(), mTextPadding, + 10 + mTextPadding, mPaint); } - if (mBackgroundImage != null) { - Rect s = new Rect(0, 0, mBackgroundImage.getWidth(), - mBackgroundImage.getHeight()); - Rect d = new Rect(0, 0, getWidth(), getHeight()); - canvas.drawBitmap(mBackgroundImage, s, d, mPaint); + mPaint.setARGB(255, 150, 150, 150); + mPaint.setStrokeWidth(4); + canvas.drawLine(0, 0, getWidth(), 0, mPaint); + + if (showControls()) { + mSliderController.onDraw(canvas); } + drawToast(canvas); + } + + public void getFilteredImage() { Bitmap filteredImage = null; if (mImageLoader != null) { filteredImage = mImageLoader.getImageForPreset(this, @@ -187,12 +223,14 @@ public class ImageShow extends View implements SliderListener { if (mShowOriginal || mFilteredImage == null) { mFilteredImage = mForegroundImage; } + } - if (mFilteredImage != null) { - Rect s = new Rect(0, 0, mFilteredImage.getWidth(), - mFilteredImage.getHeight()); - float ratio = mFilteredImage.getWidth() - / (float) mFilteredImage.getHeight(); + public void drawImage(Canvas canvas, Bitmap image) { + if (image != null) { + Rect s = new Rect(0, 0, image.getWidth(), + image.getHeight()); + float ratio = image.getWidth() + / (float) image.getHeight(); float w = getWidth(); float h = w / ratio; float ty = (getHeight() - h) / 2.0f; @@ -208,28 +246,20 @@ public class ImageShow extends View implements SliderListener { (int) (h + ty)); mImageBounds = d; - canvas.drawBitmap(mFilteredImage, s, d, mPaint); + canvas.drawBitmap(image, s, d, mPaint); } + } - if (showTitle() && getImagePreset() != null) { - mPaint.setARGB(200, 0, 0, 0); - mPaint.setTextSize(mTextSize); - - Rect textRect = new Rect(0, 0, getWidth(), mTextSize + mTextPadding); - canvas.drawRect(textRect, mPaint); - mPaint.setARGB(255, 200, 200, 200); - canvas.drawText(getImagePreset().name(), mTextPadding, - 10 + mTextPadding, mPaint); + public void drawBackground(Canvas canvas) { + if (mBackgroundImage == null) { + mBackgroundImage = mImageLoader.getBackgroundBitmap(getResources()); } - mPaint.setARGB(255, 150, 150, 150); - mPaint.setStrokeWidth(4); - canvas.drawLine(0, 0, getWidth(), 0, mPaint); - - if (showControls()) { - mSliderController.onDraw(canvas); + if (mBackgroundImage != null) { + Rect s = new Rect(0, 0, mBackgroundImage.getWidth(), + mBackgroundImage.getHeight()); + Rect d = new Rect(0, 0, getWidth(), getHeight()); + canvas.drawBitmap(mBackgroundImage, s, d, mPaint); } - - drawToast(canvas); } public void setShowControls(boolean value) { diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageSlave.java b/src/com/android/gallery3d/filtershow/imageshow/ImageSlave.java new file mode 100644 index 000000000..debaec708 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageSlave.java @@ -0,0 +1,65 @@ +package com.android.gallery3d.filtershow.imageshow; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; + +import com.android.gallery3d.filtershow.filters.ImageFilter; +import com.android.gallery3d.filtershow.presets.ImagePreset; + +public class ImageSlave extends ImageShow { + private ImageShow mMasterImageShow = null; + + public ImageSlave(Context context) { + super(context); + } + + public ImageSlave(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ImageShow getMaster() { + return mMasterImageShow; + } + + public void setMaster(ImageShow master) { + mMasterImageShow = master; + } + + public ImagePreset getImagePreset() { + return mMasterImageShow.getImagePreset(); + } + + public void setImagePreset(ImagePreset preset, boolean addToHistory) { + mMasterImageShow.setImagePreset(preset, addToHistory); + } + + public void setCurrentFilter(ImageFilter filter) { + mMasterImageShow.setCurrentFilter(filter); + } + + public ImageFilter getCurrentFilter() { + return mMasterImageShow.getCurrentFilter(); + } + + public void updateAngle() { + mMasterImageShow.setImageRotation(mImageRotation, mImageRotationZoomFactor); + } + + public boolean showTitle() { + return false; + } + + public float getImageRotation() { + return mMasterImageShow.getImageRotation(); + } + + public float getImageRotationZoomFactor() { + return mMasterImageShow.getImageRotationZoomFactor(); + } + + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + } + +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java index c4f0456cb..eb034bf10 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageStraighten.java @@ -15,8 +15,7 @@ import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; -public class ImageStraighten extends ImageShow { - private ImageShow mMasterImageShow = null; +public class ImageStraighten extends ImageSlave { private float mImageRotation = 0; private float mImageRotationZoomFactor = 0; @@ -48,26 +47,6 @@ public class ImageStraighten extends ImageShow { super(context, attrs); } - public void updateAngle() { - mMasterImageShow.setImageRotation(mImageRotation, mImageRotationZoomFactor); - } - - public void setMaster(ImageShow master) { - mMasterImageShow = master; - } - - public boolean showTitle() { - return false; - } - - public ImagePreset getImagePreset() { - return mMasterImageShow.getImagePreset(); - } - - public void setImagePreset(ImagePreset preset, boolean addToHistory) { - mMasterImageShow.setImagePreset(preset, addToHistory); - } - // /////////////////////////////////////////////////////////////////////////// // touch event handler @@ -168,7 +147,7 @@ public class ImageStraighten extends ImageShow { // so that we can fake the rotation, etc. Bitmap image = null; // mMasterImageShow.mFilteredImage; if (image == null) { - image = mMasterImageShow.mForegroundImage; + image = getMaster().mForegroundImage; } if (image == null) { return; diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java new file mode 100644 index 000000000..1c5a9b50e --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java @@ -0,0 +1,134 @@ +package com.android.gallery3d.filtershow.imageshow; + +import com.android.gallery3d.filtershow.presets.ImagePreset; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.GestureDetector.OnDoubleTapListener; +import android.view.GestureDetector.OnGestureListener; +import android.view.MotionEvent; + +public class ImageZoom extends ImageSlave implements OnGestureListener, OnDoubleTapListener { + private boolean mTouchDown = false; + private boolean mZoomedIn = false; + private Rect mZoomBounds = null; + private GestureDetector mGestureDetector = null; + + public ImageZoom(Context context) { + super(context); + setupGestureDetector(context); + } + + public ImageZoom(Context context, AttributeSet attrs) { + super(context, attrs); + setupGestureDetector(context); + } + + public void setupGestureDetector(Context context) { + mGestureDetector = new GestureDetector(context, this); + } + + public boolean onTouchEvent(MotionEvent event) { + boolean ret = mGestureDetector.onTouchEvent(event); + ret = super.onTouchEvent(event); + return ret; + } + + public void onTouchDown(float x, float y) { + super.onTouchDown(x, y); + if (mZoomedIn || mTouchDown) { + return; + } + mTouchDown = true; + Rect originalBounds = mImageLoader.getOriginalBounds(); + Rect imageBounds = getImageBounds(); + float touchX = x - imageBounds.left; + float touchY = y - imageBounds.top; + + float w = originalBounds.width(); + float h = originalBounds.height(); + float ratio = w / h; + int mw = getWidth() / 2; + int mh = getHeight() / 2; + int cx = (int) (w / 2); + int cy = (int) (h / 2); + cx = (int) (touchX / imageBounds.width() * w); + cy = (int) (touchY / imageBounds.height() * h); + int left = cx - mw; + int top = cy - mh; + mZoomBounds = new Rect(left, top, left + mw * 2, top + mh * 2); + } + + public void onTouchUp() { + mTouchDown = false; + } + + public void onDraw(Canvas canvas) { + drawBackground(canvas); + Bitmap filteredImage = null; + if ((mZoomedIn ||mTouchDown) && mImageLoader != null) { + filteredImage = mImageLoader.getScaleOneImageForPreset(this, getImagePreset(), mZoomBounds, false); + } else { + getFilteredImage(); + filteredImage = mFilteredImage; + } + drawImage(canvas, filteredImage); + if (showControls()) { + mSliderController.onDraw(canvas); + } + + drawToast(canvas); + } + + // TODO: move back some of that touch handling to a superclass / refactor + // SlideController into a more generic gesture detector + @Override + public boolean onDown(MotionEvent arg0) { + return false; + } + + @Override + public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) { + return false; + } + + @Override + public void onLongPress(MotionEvent arg0) { + } + + @Override + public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) { + return false; + } + + @Override + public void onShowPress(MotionEvent arg0) { + } + + @Override + public boolean onSingleTapUp(MotionEvent arg0) { + return false; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent arg0) { + return false; + } + + @Override + public boolean onDoubleTap(MotionEvent arg0) { + mZoomedIn = !mZoomedIn; + invalidate(); + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent arg0) { + return false; + } +}
\ No newline at end of file diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java index 8091c1e7b..3da058bc7 100644 --- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java +++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java @@ -4,6 +4,7 @@ package com.android.gallery3d.filtershow.ui; import com.android.gallery3d.filtershow.filters.ImageFilter; import com.android.gallery3d.filtershow.filters.ImageFilterCurves; import com.android.gallery3d.filtershow.imageshow.ImageShow; +import com.android.gallery3d.filtershow.imageshow.ImageSlave; import com.android.gallery3d.filtershow.presets.ImagePreset; import com.android.gallery3d.filtershow.ui.ControlPoint; import com.android.gallery3d.filtershow.ui.Spline; @@ -22,7 +23,7 @@ import android.view.View; import android.widget.PopupMenu; import android.widget.Toast; -public class ImageCurves extends ImageShow { +public class ImageCurves extends ImageSlave { private static final String LOGTAG = "ImageCurves"; Paint gPaint = new Paint(); @@ -31,7 +32,6 @@ public class ImageCurves extends ImageShow { float[] mAppliedCurve = new float[256]; private boolean mDidAddPoint = false; private boolean mDidDelete = false; - private ImageShow mMasterImageShow = null; private ControlPoint mCurrentControlPoint = null; private boolean mUseRed = true; private boolean mUseGreen = true; @@ -47,10 +47,6 @@ public class ImageCurves extends ImageShow { resetCurve(); } - public void setMaster(ImageShow master) { - mMasterImageShow = master; - } - public boolean showTitle() { return false; } @@ -68,7 +64,7 @@ public class ImageCurves extends ImageShow { } public void reloadCurve() { - if (mMasterImageShow != null) { + if (getMaster() != null) { String filterName = getFilterName(); ImageFilterCurves filter = (ImageFilterCurves) getImagePreset() .getFilter(filterName); @@ -86,27 +82,11 @@ public class ImageCurves extends ImageShow { mSpline.addPoint(0.0f, 1.0f); mSpline.addPoint(1.0f, 0.0f); - if (mMasterImageShow != null) { + if (getMaster() != null) { applyNewCurve(); } } - public ImagePreset getImagePreset() { - return mMasterImageShow.getImagePreset(); - } - - public void setImagePreset(ImagePreset preset, boolean addToHistory) { - mMasterImageShow.setImagePreset(preset, addToHistory); - } - - public float getImageRotation() { - return mMasterImageShow.getImageRotation(); - } - - public float getImageRotationZoomFactor() { - return mMasterImageShow.getImageRotationZoomFactor(); - } - public void onDraw(Canvas canvas) { super.onDraw(canvas); diff --git a/src/com/android/gallery3d/filtershow/ui/SliderController.java b/src/com/android/gallery3d/filtershow/ui/SliderController.java index b5b9c81ec..f2f0df30b 100644 --- a/src/com/android/gallery3d/filtershow/ui/SliderController.java +++ b/src/com/android/gallery3d/filtershow/ui/SliderController.java @@ -116,6 +116,9 @@ public class SliderController { mCurrentX = x; mCurrentY = y; mMode = MODES.DOWN; + if (mListener != null) { + mListener.onTouchDown(x, y); + } } public void setActionMove(float x, float y) { @@ -131,6 +134,9 @@ public class SliderController { public void setActionUp() { mMode = MODES.UP; mOriginalValue = computeValue(); + if (mListener != null) { + mListener.onTouchUp(); + } } public void setNoAction() { diff --git a/src/com/android/gallery3d/filtershow/ui/SliderListener.java b/src/com/android/gallery3d/filtershow/ui/SliderListener.java index 67e28de0e..b11966ece 100644 --- a/src/com/android/gallery3d/filtershow/ui/SliderListener.java +++ b/src/com/android/gallery3d/filtershow/ui/SliderListener.java @@ -3,4 +3,6 @@ package com.android.gallery3d.filtershow.ui; public interface SliderListener { public void onNewValue(int value); + public void onTouchDown(float x, float y); + public void onTouchUp(); } |