OSDN Git Service

add movable vignette
authorJohn Hoford <hoford@google.com>
Sat, 16 Feb 2013 17:20:59 +0000 (09:20 -0800)
committerJohn Hoford <hoford@google.com>
Tue, 19 Feb 2013 23:25:43 +0000 (15:25 -0800)
Change-Id: I54f2fccd0d748ca4c908d5b0f3c3ef7349cd686d

14 files changed:
jni/filters/vignette.c
res/layout/filtershow_vignette_editor.xml [new file with mode: 0644]
res/values/filtershow_ids.xml
src/com/android/gallery3d/filtershow/editors/EditorVignette.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java
src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java
src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
src/com/android/gallery3d/filtershow/imageshow/ImageTinyPlanet.java
src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/imageshow/Oval.java [new file with mode: 0644]
src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java

index 2799ff0..b9ee3ff 100644 (file)
  */
 
 #include "filters.h"
+#include <math.h>
 
 static int* gVignetteMap = 0;
 static int gVignetteWidth = 0;
 static int gVignetteHeight = 0;
 
-__inline__ void createVignetteMap(int w, int h)
-{
-    if (gVignetteMap && (gVignetteWidth != w || gVignetteHeight != h))
-    {
-        free(gVignetteMap);
-        gVignetteMap = 0;
-    }
-    if (gVignetteMap == 0)
-    {
-        gVignetteWidth = w;
-        gVignetteHeight = h;
-
-        int cx = w / 2;
-        int cy = h / 2;
-        int i, j;
-
-        gVignetteMap = malloc(w * h * sizeof(int));
-        float maxDistance = cx * cx * 2.0f;
-        for (i = 0; i < w; i++)
-        {
-            for (j = 0; j < h; j++)
-            {
-                float distance = (cx - i) * (cx - i) + (cy - j) * (cy - j);
-                gVignetteMap[j * w + i] = (int) (distance / maxDistance * 255);
-            }
-        }
-    }
-}
-
-void JNIFUNCF(ImageFilterVignette, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat strength)
+void JNIFUNCF(ImageFilterVignette, nativeApplyFilter, jobject bitmap, jint width, jint height, jint centerx, jint centery, jfloat radiusx, jfloat radiusy, jfloat strength)
 {
     char* destination = 0;
     AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
-    createVignetteMap(width, height);
     int i;
     int len = width * height * 4;
     int vignette = 0;
+    float d = centerx;
+    if (radiusx == 0) radiusx = 10;
+    if (radiusy == 0) radiusy = 10;
+    float scalex = 1/radiusx;
+    float scaley = 1/radiusy;
 
     for (i = 0; i < len; i += 4)
     {
-        vignette = (int) (strength * gVignetteMap[i / 4]);
+        int p = i/4;
+        float x = ((p%width)-centerx)*scalex;
+        float y = ((p/width)-centery)*scaley;
+        float dist = sqrt(x*x+y*y)-1;
+        vignette = (int) (strength*256*MAX(dist,0));
         destination[RED] = CLAMP(destination[RED] - vignette);
         destination[GREEN] = CLAMP(destination[GREEN] - vignette);
         destination[BLUE] = CLAMP(destination[BLUE] - vignette);
diff --git a/res/layout/filtershow_vignette_editor.xml b/res/layout/filtershow_vignette_editor.xml
new file mode 100644 (file)
index 0000000..6e57559
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:iconbutton="http://schemas.android.com/apk/res/com.android.gallery3d"
+     android:id="@+id/tinyPlanetEditor"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_weight="1" >
+
+    <com.android.gallery3d.filtershow.imageshow.ImageVignette
+        android:id="@+id/imageVignette"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+        <com.android.gallery3d.filtershow.CenteredLinearLayout
+            xmlns:custom="http://schemas.android.com/apk/res/com.android.gallery3d"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal|bottom"
+            android:background="@android:color/transparent"
+            custom:max_width="600dip"
+            android:orientation="vertical">
+
+            <SeekBar
+                android:id="@+id/filterSeekBar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="bottom"
+                android:padding="16dip"/>
+    </com.android.gallery3d.filtershow.CenteredLinearLayout>
+ </FrameLayout>
\ No newline at end of file
index 786d7ee..ba31834 100644 (file)
@@ -40,4 +40,5 @@
     <item type="id" name="editorDraw" />
     <item type="id" name="editorRedEye" />
     <item type="id" name="imageOnlyEditor" />
+    <item type="id" name="vignetteEditor" />
 </resources>
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
new file mode 100644 (file)
index 0000000..a60c168
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.editors;
+
+import android.content.Context;
+import android.util.Log;
+import android.widget.FrameLayout;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTinyPlanetRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterVignetteRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageVignette;
+
+public class EditorVignette extends BasicEditor {
+    public static final int ID = R.id.vignetteEditor;
+    private static final String LOGTAG = "EditorVignettePlanet";
+    ImageVignette mImageVignette;
+
+    public EditorVignette() {
+        super(ID, R.layout.filtershow_vignette_editor, R.id.imageVignette);
+    }
+
+    @Override
+    public void createEditor(Context context, FrameLayout frameLayout) {
+        super.createEditor(context, frameLayout);
+        mImageVignette = (ImageVignette) mImageShow;
+        mImageVignette.setEditor(this);
+    }
+
+    @Override
+    public void reflectCurrentFilter() {
+        super.reflectCurrentFilter();
+
+        FilterRepresentation rep = getLocalRepresentation();
+        if (rep != null && getLocalRepresentation() instanceof FilterVignetteRepresentation) {
+            FilterVignetteRepresentation drawRep = (FilterVignetteRepresentation) rep;
+            mImageVignette.setRepresentation(drawRep);
+        }
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java
new file mode 100644 (file)
index 0000000..eef54ef
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.filters;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.editors.EditorVignette;
+import com.android.gallery3d.filtershow.imageshow.Oval;
+
+public class FilterVignetteRepresentation extends FilterBasicRepresentation implements Oval {
+    private static final String LOGTAG = "FilterVignetteRepresentation";
+    private float mCenterX = Float.NaN;
+    private float mCenterY;
+    private float mRadiusX = Float.NaN;
+    private float mRadiusY;
+
+    public FilterVignetteRepresentation() {
+        super("Vignette", -100, 50, 100);
+        setShowParameterValue(true);
+        setPriority(FilterRepresentation.TYPE_VIGNETTE);
+        setTextId(R.string.vignette);
+        setButtonId(R.id.vignetteEditor);
+        setEditorId(EditorVignette.ID);
+        setName("Vignette");
+        setFilterClass(ImageFilterVignette.class);
+
+        setMinimum(-100);
+        setMaximum(100);
+        setDefaultValue(0);
+    }
+
+    @Override
+    public void useParametersFrom(FilterRepresentation a) {
+        super.useParametersFrom(a);
+        mCenterX = ((FilterVignetteRepresentation) a).mCenterX;
+        mCenterY = ((FilterVignetteRepresentation) a).mCenterY;
+        mRadiusX = ((FilterVignetteRepresentation) a).mRadiusX;
+        mRadiusY = ((FilterVignetteRepresentation) a).mRadiusY;
+    }
+
+    @Override
+    public FilterRepresentation clone() throws CloneNotSupportedException {
+        FilterVignetteRepresentation representation = (FilterVignetteRepresentation) super
+                .clone();
+        representation.mCenterX = mCenterX;
+        representation.mCenterY = mCenterY;
+
+        return representation;
+    }
+
+    @Override
+    public void setCenter(float centerX, float centerY) {
+        mCenterX = centerX;
+        mCenterY = centerY;
+    }
+
+    @Override
+    public float getCenterX() {
+        return mCenterX;
+    }
+
+    @Override
+    public float getCenterY() {
+        return mCenterY;
+    }
+
+    @Override
+    public void setRadius(float radiusX, float radiusY) {
+        mRadiusX = radiusX;
+        mRadiusY = radiusY;
+    }
+
+    @Override
+    public void setRadiusX(float radiusX) {
+        mRadiusX = radiusX;
+    }
+
+    @Override
+    public void setRadiusY(float radiusY) {
+        mRadiusY = radiusY;
+    }
+
+    @Override
+    public float getRadiusX() {
+        return mRadiusX;
+    }
+
+    @Override
+    public float getRadiusY() {
+        return mRadiusY;
+    }
+
+    public boolean isCenterSet() {
+        return mCenterX != Float.NaN;
+    }
+
+    @Override
+    public boolean isNil() {
+        return getValue() == 0;
+    }
+}
index 465d90b..9ff737e 100644 (file)
 
 package com.android.gallery3d.filtershow.filters;
 
-import com.android.gallery3d.R;
-
 import android.graphics.Bitmap;
+import android.graphics.Matrix;
+
 import com.android.gallery3d.app.Log;
 
 public class ImageFilterVignette extends SimpleImageFilter {
-
     private static final String LOGTAG = "ImageFilterVignette";
 
     public ImageFilterVignette() {
         mName = "Vignette";
     }
 
+    @Override
     public FilterRepresentation getDefaultRepresentation() {
-        FilterBasicRepresentation representation =
-                (FilterBasicRepresentation) super.getDefaultRepresentation();
-        representation.setName("Vignette");
-        representation.setFilterClass(ImageFilterVignette.class);
-        representation.setPriority(FilterRepresentation.TYPE_VIGNETTE);
-        representation.setTextId(R.string.vignette);
-        representation.setButtonId(R.id.vignetteButton);
-
-        representation.setMinimum(-100);
-        representation.setMaximum(100);
-        representation.setDefaultValue(0);
-
+        FilterVignetteRepresentation representation = new FilterVignetteRepresentation();
         return representation;
     }
 
-    native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float strength);
+    native protected void nativeApplyFilter(
+            Bitmap bitmap, int w, int h, int cx, int cy, float radx, float rady, float strength);
+
+    private float calcRadius(float cx, float cy, int w, int h) {
+        float d = cx;
+        if (d < (w - cx)) {
+            d = w - cx;
+        }
+        if (d < cy) {
+            d = cy;
+        }
+        if (d < (h - cy)) {
+            d = h - cy;
+        }
+        return d * d * 2.0f;
+    }
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
-        if (getParameters() == null) {
+        FilterVignetteRepresentation rep = (FilterVignetteRepresentation) getParameters();
+        if (rep == null) {
             return bitmap;
         }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        float value = getParameters().getValue() / 100.0f;
-        nativeApplyFilter(bitmap, w, h, value);
-
+        float value = rep.getValue() / 100.0f;
+        float cx = w / 2;
+        float cy = h / 2;
+        float r = calcRadius(cx, cy, w, h);
+        float rx = r;
+        float ry = r;
+        if (rep.isCenterSet()) {
+            Matrix m = getOriginalToScreenMatrix(w, h);
+            cx = rep.getCenterX();
+            cy = rep.getCenterY();
+            float[] center = new float[] { cx, cy };
+            m.mapPoints(center);
+            cx = center[0];
+            cy = center[1];
+            rx = m.mapRadius(rep.getRadiusX());
+            ry = m.mapRadius(rep.getRadiusY());
+         }
+        nativeApplyFilter(bitmap, w, h, (int) cx, (int) cy, rx, ry, value);
         return bitmap;
     }
 }
diff --git a/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java b/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java
new file mode 100644 (file)
index 0000000..2479188
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * 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.imageshow;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
+import android.graphics.RectF;
+import android.graphics.Shader;
+
+import com.android.gallery3d.R;
+
+public class EclipseControl {
+    private float mCenterX = Float.NaN;
+    private float mCenterY = 0;
+    private float mRadiusX = 200;
+    private float mRadiusY = 300;
+    private static int MIN_TOUCH_DIST = 80;// should be a resource & in dips
+
+    private float[] handlex = new float[9];
+    private float[] handley = new float[9];
+    private int mSliderColor;
+    private int mCenterDotSize = 40;
+    private float mDownX;
+    private float mDownY;
+    private float mDownCenterX;
+    private float mDownCenterY;
+    private float mDownRadiusX;
+    private float mDownRadiusY;
+    private Matrix mScrToImg;
+
+    private final static int HAN_CENTER = 0;
+    private final static int HAN_NORTH = 7;
+    private final static int HAN_NE = 8;
+    private final static int HAN_EAST = 1;
+    private final static int HAN_SE = 2;
+    private final static int HAN_SOUTH = 3;
+    private final static int HAN_SW = 4;
+    private final static int HAN_WEST = 5;
+    private final static int HAN_NW = 6;
+
+    public EclipseControl(Context context) {
+        mSliderColor = context.getResources().getColor(R.color.slider_line_color);
+    }
+
+    public void setRadius(float x, float y) {
+        mRadiusX = x;
+        mRadiusY = y;
+    }
+
+    public void setCenter(float x, float y) {
+        mCenterX = x;
+        mCenterY = y;
+    }
+
+    public int getCloseHandle(float x, float y) {
+        float min = Float.MAX_VALUE;
+        int handle = -1;
+        for (int i = 0; i < handlex.length; i++) {
+            float dx = handlex[i] - x;
+            float dy = handley[i] - y;
+            float dist = dx * dx + dy * dy;
+            if (dist < min) {
+                min = dist;
+                handle = i;
+            }
+        }
+
+        if (min < MIN_TOUCH_DIST * MIN_TOUCH_DIST) {
+            return handle;
+        }
+        for (int i = 0; i < handlex.length; i++) {
+            float dx = handlex[i] - x;
+            float dy = handley[i] - y;
+            float dist = (float) Math.sqrt(dx * dx + dy * dy);
+        }
+
+        return -1;
+    }
+
+    public void setScrToImageMatrix(Matrix scrToImg) {
+        mScrToImg = scrToImg;
+    }
+
+    public void actionDown(float x, float y, Oval oval) {
+        float[] point = new float[] {
+                x, y };
+        mScrToImg.mapPoints(point);
+        mDownX = point[0];
+        mDownY = point[1];
+        mDownCenterX = oval.getCenterX();
+        mDownCenterY = oval.getCenterY();
+        mDownRadiusX = oval.getRadiusX();
+        mDownRadiusY = oval.getRadiusY();
+    }
+
+    public void actionMove(int handle, float x, float y, Oval oval) {
+        float[] point = new float[] {
+                x, y };
+        mScrToImg.mapPoints(point);
+        x = point[0];
+        y = point[1];
+        int sign = 1;
+        switch (handle) {
+            case HAN_CENTER:
+                float ctrdx = mDownX - mDownCenterX;
+                float ctrdy = mDownY - mDownCenterY;
+                oval.setCenter(x - ctrdx, y - ctrdy);
+                // setRepresentation(mVignetteRep);
+                break;
+            case HAN_NORTH:
+                sign = -1;
+            case HAN_SOUTH:
+                float raddy = mDownRadiusY - Math.abs(mDownY - mDownCenterY);
+                oval.setRadiusY(Math.abs(y - oval.getCenterY() + sign * raddy));
+                break;
+            case HAN_EAST:
+                sign = -1;
+            case HAN_WEST:
+                float raddx = mDownRadiusX - Math.abs(mDownX - mDownCenterX);
+                oval.setRadiusX(Math.abs(x - oval.getCenterX() - sign * raddx));
+                break;
+            case HAN_SE:
+            case HAN_NE:
+            case HAN_SW:
+            case HAN_NW:
+                float sin45 = (float) Math.sin(45);
+                float dr = (mDownRadiusX + mDownRadiusY) * sin45;
+                float ctr_dx = mDownX - mDownCenterX;
+                float ctr_dy = mDownY - mDownCenterY;
+                float downRad = Math.abs(ctr_dx) + Math.abs(ctr_dy) - dr;
+                float rx = oval.getRadiusX();
+                float ry = oval.getRadiusY();
+                float r = (Math.abs(rx) + Math.abs(ry)) * sin45;
+                float dx = x - oval.getCenterX();
+                float dy = y - oval.getCenterY();
+                float nr = Math.abs(Math.abs(dx) + Math.abs(dy) - downRad);
+                oval.setRadius(rx * nr / r, ry * nr / r);
+
+                break;
+        }
+    }
+
+    void paintPoint(Canvas canvas, float x, float y) {
+        if (x == Float.NaN) {
+            return;
+        }
+
+        Paint paint = new Paint();
+
+        paint.setStyle(Paint.Style.FILL);
+        paint.setColor(Color.BLUE);
+        int[] colors3 = new int[] {
+                mSliderColor, mSliderColor, 0x66000000, 0 };
+        RadialGradient g = new RadialGradient(x, y, mCenterDotSize, colors3, new float[] {
+                0, .3f, .31f, 1 }, Shader.TileMode.CLAMP);
+        paint.setShader(g);
+        canvas.drawCircle(x, y, mCenterDotSize, paint);
+    }
+
+    void paintRadius(Canvas canvas, float cx, float cy, float rx, float ry) {
+        if (cx == Float.NaN) {
+            return;
+        }
+        int mSliderColor = 0xFF33B5E5;
+        Paint paint = new Paint();
+        RectF rect = new RectF(cx - rx, cy - ry, cx + rx, cy + ry);
+        paint.setAntiAlias(true);
+        paint.setStyle(Paint.Style.STROKE);
+        paint.setStrokeWidth(6);
+        paint.setColor(Color.BLACK);
+        paintOvallines(canvas, rect, paint, cx, cy, rx, ry);
+
+        paint.setStrokeWidth(3);
+        paint.setColor(Color.WHITE);
+        paintOvallines(canvas, rect, paint, cx, cy, rx, ry);
+    }
+
+    public void paintOvallines(
+            Canvas canvas, RectF rect, Paint paint, float cx, float cy, float rx, float ry) {
+        canvas.drawOval(rect, paint);
+        float da = 4;
+        float arclen = da + da;
+        for (int i = 0; i < 361; i += 90) {
+            float dx = rx + 10;
+            float dy = ry + 10;
+            rect.left = cx - dx;
+            rect.top = cy - dy;
+            rect.right = cx + dx;
+            rect.bottom = cy + dy;
+            canvas.drawArc(rect, i - da, arclen, false, paint);
+            dx = rx - 10;
+            dy = ry - 10;
+            rect.left = cx - dx;
+            rect.top = cy - dy;
+            rect.right = cx + dx;
+            rect.bottom = cy + dy;
+            canvas.drawArc(rect, i - da, arclen, false, paint);
+        }
+        da *= 2;
+        for (int i = 45; i < 361; i += 90) {
+            double angle = Math.PI * i / 180.;
+            float x = cx + (float) (rx * Math.cos(angle));
+            float y = cy + (float) (ry * Math.sin(angle));
+            canvas.drawRect(x - da, y - da, x + da, y + da, paint);
+        }
+        rect.left = cx - rx;
+        rect.top = cy - ry;
+        rect.right = cx + rx;
+        rect.bottom = cy + ry;
+    }
+
+    public void fillHandles(Canvas canvas, float cx, float cy, float rx, float ry) {
+        handlex[0] = cx;
+        handley[0] = cy;
+        int k = 1;
+
+        for (int i = 0; i < 360; i += 45) {
+            double angle = Math.PI * i / 180.;
+
+            float x = cx + (float) (rx * Math.cos(angle));
+            float y = cy + (float) (ry * Math.sin(angle));
+            handlex[k] = x;
+            handley[k] = y;
+
+            k++;
+        }
+    }
+
+    public void draw(Canvas canvas) {
+        paintRadius(canvas, mCenterX, mCenterY, mRadiusX, mRadiusY);
+        fillHandles(canvas, mCenterX, mCenterY, mRadiusX, mRadiusY);
+        paintPoint(canvas, mCenterX, mCenterY);
+    }
+}
index 06b055d..625cdbe 100644 (file)
@@ -75,13 +75,9 @@ public abstract class ImagePoint extends ImageShow {
         paint.setColor(Color.RED);
         paint.setStrokeWidth(2);
 
-        GeometryMetadata geo = getImagePreset().mGeoData;
-        Matrix originalToScreen = geo.getOriginalToScreen(false,
-                mImageLoader.getOriginalBounds().width(),
-                mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
-        Matrix originalRotateToScreen = geo.getOriginalToScreen(true,
-                mImageLoader.getOriginalBounds().width(),
-                mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
+        Matrix originalToScreen = getImageToScreenMatrix(false);
+        Matrix originalRotateToScreen = getImageToScreenMatrix(true);
+
         if (mRedEyeRep != null) {
             for (FilterPoint candidate : mRedEyeRep.getCandidates()) {
                 drawPoint(candidate, canvas, originalToScreen, originalRotateToScreen, paint);
index c3ff5e1..9e66798 100644 (file)
@@ -62,16 +62,8 @@ public class ImageRedEye extends ImagePoint {
         if (event.getAction() == MotionEvent.ACTION_UP) {
             if (mCurrentRect != null) {
                 // transform to original coordinates
-                GeometryMetadata geo = getImagePreset().mGeoData;
-                Matrix originalToScreen = geo.getOriginalToScreen(true,
-                        mImageLoader.getOriginalBounds().width(),
-                        mImageLoader.getOriginalBounds().height(),
-                        getWidth(), getHeight());
-                Matrix originalNoRotateToScreen = geo.getOriginalToScreen(false,
-                        mImageLoader.getOriginalBounds().width(),
-                        mImageLoader.getOriginalBounds().height(),
-                        getWidth(), getHeight());
-
+                Matrix originalNoRotateToScreen = getImageToScreenMatrix(false);
+                Matrix originalToScreen = getImageToScreenMatrix(true);
                 Matrix invert = new Matrix();
                 originalToScreen.invert(invert);
                 RectF r = new RectF(mCurrentRect);
index 4637568..94df06a 100644 (file)
@@ -20,6 +20,7 @@ import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -269,6 +270,34 @@ public class ImageShow extends View implements OnGestureListener,
         return GeometryMath.roundNearest(getImagePreset().mGeoData.getPreviewCropBounds());
     }
 
+    /* consider moving the following 2 methods into a subclass */
+    /**
+     * This function calculates a Image to Screen Transformation matrix
+     *
+     * @param reflectRotation set true if you want the rotation encoded
+     * @return Image to Screen transformation matrix
+     */
+    protected Matrix getImageToScreenMatrix(boolean reflectRotation) {
+        GeometryMetadata geo = getImagePreset().mGeoData;
+        Matrix m = geo.getOriginalToScreen(reflectRotation,
+                mImageLoader.getOriginalBounds().width(),
+                mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
+        return m;
+    }
+
+    /**
+     * This function calculates a to Screen Image Transformation matrix
+     *
+     * @param reflectRotation set true if you want the rotation encoded
+     * @return Screen to Image transformation matrix
+     */
+    protected Matrix getScreenToImageMatrix(boolean reflectRotation) {
+        Matrix m = getImageToScreenMatrix(reflectRotation);
+        Matrix invert = new Matrix();
+        m.invert(invert);
+        return invert;
+    }
+
     public Rect getDisplayedImageBounds() {
         return mImageBounds;
     }
index 3e95d4e..3795d1f 100644 (file)
@@ -22,6 +22,7 @@ import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 
+import com.android.gallery3d.filtershow.editors.BasicEditor;
 import com.android.gallery3d.filtershow.editors.EditorTinyPlanet;
 import com.android.gallery3d.filtershow.filters.FilterCurvesRepresentation;
 import com.android.gallery3d.filtershow.filters.FilterTinyPlanetRepresentation;
@@ -37,7 +38,7 @@ public class ImageTinyPlanet extends ImageShow {
     private float mCenterY = 0;
     private float mStartAngle = 0;
     private FilterTinyPlanetRepresentation mTinyPlanetRep;
-    private EditorTinyPlanet mEditorTinyPlanet;
+    private BasicEditor mEditorTinyPlanet;
 
     public ImageTinyPlanet(Context context) {
         super(context);
@@ -94,7 +95,7 @@ public class ImageTinyPlanet extends ImageShow {
         mTinyPlanetRep = tinyPlanetRep;
     }
 
-    public void setEditor(EditorTinyPlanet editorTinyPlanet) {
+    public void setEditor(BasicEditor editorTinyPlanet) {
         mEditorTinyPlanet = editorTinyPlanet;
     }
 
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java
new file mode 100644 (file)
index 0000000..d56cc47
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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.imageshow;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.gallery3d.filtershow.editors.EditorVignette;
+import com.android.gallery3d.filtershow.filters.FilterVignetteRepresentation;
+
+public class ImageVignette extends ImageShow {
+    private static final String LOGTAG = "ImageVignette";
+
+    private FilterVignetteRepresentation mVignetteRep;
+    private EditorVignette mEditorVignette;
+
+    private int mActiveHandle = -1;
+
+    EclipseControl mElipse;
+
+    public ImageVignette(Context context) {
+        super(context);
+        mElipse = new EclipseControl(context);
+    }
+
+    public ImageVignette(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mElipse = new EclipseControl(context);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        int mask = event.getActionMasked();
+        if (MotionEvent.ACTION_UP == mask) {
+            mActiveHandle = -1;
+        }
+        if (MotionEvent.ACTION_DOWN == mask && event.getPointerCount() == 1) {
+            mActiveHandle = mElipse.getCloseHandle(event.getX(), event.getY());
+        }
+        if (mActiveHandle == -1 || event.getPointerCount() > 1) {
+            mActiveHandle = -1;
+
+            return super.onTouchEvent(event);
+        }
+        float x = event.getX();
+        float y = event.getY();
+
+        mElipse.setScrToImageMatrix(getScreenToImageMatrix(true));
+
+        switch (mask) {
+            case (MotionEvent.ACTION_DOWN):
+                mElipse.actionDown(x, y, mVignetteRep);
+                break;
+            case (MotionEvent.ACTION_UP):
+            case (MotionEvent.ACTION_MOVE):
+
+                mElipse.actionMove(mActiveHandle, x, y, mVignetteRep);
+                setRepresentation(mVignetteRep);
+                break;
+        }
+        resetImageCaches(this);
+        invalidate();
+        mEditorVignette.commitLocalRepresentation();
+        return true;
+    }
+
+    public void setRepresentation(FilterVignetteRepresentation vignetteRep) {
+        mVignetteRep = vignetteRep;
+        Matrix toImg = getScreenToImageMatrix(false);
+        Matrix toScr = new Matrix();
+        toImg.invert(toScr);
+
+        float[] c = new float[] {
+                mVignetteRep.getCenterX(), mVignetteRep.getCenterY() };
+        if (Float.isNaN(c[0])) {
+            float cx = mImageLoader.getOriginalBounds().width() / 2;
+            float cy = mImageLoader.getOriginalBounds().height() / 2;
+            float rx = cx * .8f;
+            float ry = cy * .8f;
+            mVignetteRep.setCenter(cx, cy);
+            mVignetteRep.setRadius(rx, ry);
+
+            c[0] = cx;
+            c[1] = cy;
+            toScr.mapPoints(c);
+
+            mElipse.setCenter(c[0], c[1]);
+            mElipse.setRadius(c[0] * 0.8f, c[1] * 0.8f);
+        } else {
+
+            toScr.mapPoints(c);
+
+            mElipse.setCenter(c[0], c[1]);
+            mElipse.setRadius(toScr.mapRadius(mVignetteRep.getRadiusX()),
+                    toScr.mapRadius(mVignetteRep.getRadiusY()));
+        }
+    }
+
+    public void setEditor(EditorVignette editorVignette) {
+        mEditorVignette = editorVignette;
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        mElipse.draw(canvas);
+
+    }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/Oval.java b/src/com/android/gallery3d/filtershow/imageshow/Oval.java
new file mode 100644 (file)
index 0000000..28f278f
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.imageshow;
+
+public interface Oval {
+    void setCenter(float x, float y);
+    void setRadius(float w, float h);
+    float getCenterX();
+    float getCenterY();
+    float getRadiusX();
+    float getRadiusY();
+    void setRadiusY(float y);
+    void setRadiusX(float x);
+
+}
index 67ccf9c..92962cb 100644 (file)
@@ -28,6 +28,7 @@ public class EditorManager {
         editorPlaceHolder.addEditor(new EditorCurves());
         editorPlaceHolder.addEditor(new EditorTinyPlanet());
         editorPlaceHolder.addEditor(new EditorDraw());
+        editorPlaceHolder.addEditor(new EditorVignette());
     }
 
 }