summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jni/Android.mk1
-rw-r--r--jni/filters/edge.c126
-rw-r--r--res/values/filtershow_ids.xml1
-rw-r--r--res/values/filtershow_strings.xml2
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java4
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java40
6 files changed, 173 insertions, 1 deletions
diff --git a/jni/Android.mk b/jni/Android.mk
index 8a2fc9e18..6f12b3ef4 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -29,6 +29,7 @@ LOCAL_SRC_FILES := filters/bw.c \
filters/gradient.c \
filters/saturated.c \
filters/exposure.c \
+ filters/edge.c \
filters/contrast.c \
filters/hue.c \
filters/shadows.c \
diff --git a/jni/filters/edge.c b/jni/filters/edge.c
new file mode 100644
index 000000000..9f5d88f77
--- /dev/null
+++ b/jni/filters/edge.c
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#include <math.h>
+#include "filters.h"
+
+void JNIFUNCF(ImageFilterEdge, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat p)
+{
+ char* destination = 0;
+ AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
+
+ // using contrast function:
+ // f(v) = exp(-alpha * v^beta)
+ // use beta ~ 1
+
+ float const alpha = 5.0f;
+ float const beta = p;
+ float const c_min = 100.0f;
+ float const c_max = 500.0f;
+
+ // pixels must be 4 bytes
+ char * dst = destination;
+
+ int j, k;
+ char * ptr = destination;
+ int row_stride = 4 * width;
+
+ // set 2 row buffer (avoids bitmap copy)
+ int buf_len = 2 * row_stride;
+ char buf[buf_len];
+ int buf_row_ring = 0;
+
+ // set initial buffer to black
+ memset(buf, 0, buf_len * sizeof(char));
+ for (j = 3; j < buf_len; j+=4) {
+ *(buf + j) = 255; // set initial alphas
+ }
+
+ // apply sobel filter
+ for (j = 1; j < height - 1; j++) {
+
+ for (k = 1; k < width - 1; k++){
+ int loc = j * row_stride + k * 4;
+
+ float bestx = 0.0f;
+ int l;
+ for (l = 0; l < 3; l++) {
+ float tmp = 0.0f;
+ tmp += *(ptr + (loc - row_stride + 4 + l));
+ tmp += *(ptr + (loc + 4 + l)) * 2.0f;
+ tmp += *(ptr + (loc + row_stride + 4 + l));
+ tmp -= *(ptr + (loc - row_stride - 4 + l));
+ tmp -= *(ptr + (loc - 4 + l)) * 2.0f;
+ tmp -= *(ptr + (loc + row_stride - 4 + l));
+ if (fabs(tmp) > fabs(bestx)) {
+ bestx = tmp;
+ }
+ }
+
+ float besty = 0.0f;
+ for (l = 0; l < 3; l++) {
+ float tmp = 0.0f;
+ tmp -= *(ptr + (loc - row_stride - 4 + l));
+ tmp -= *(ptr + (loc - row_stride + l)) * 2.0f;
+ tmp -= *(ptr + (loc - row_stride + 4 + l));
+ tmp += *(ptr + (loc + row_stride - 4 + l));
+ tmp += *(ptr + (loc + row_stride + l)) * 2.0f;
+ tmp += *(ptr + (loc + row_stride + 4 + l));
+ if (fabs(tmp) > fabs(besty)) {
+ besty = tmp;
+ }
+ }
+
+ // compute gradient magnitude
+ float mag = sqrt(bestx * bestx + besty * besty);
+
+ // clamp
+ mag = MIN(MAX(c_min, mag), c_max);
+
+ // scale to [0, 1]
+ mag = (mag - c_min) / (c_max - c_min);
+
+ float ret = 1.0f - exp (- alpha * pow(mag, beta));
+ ret = 255 * ret;
+
+ int off = k * 4;
+ *(buf + buf_row_ring + off) = ret;
+ *(buf + buf_row_ring + off + 1) = ret;
+ *(buf + buf_row_ring + off + 2) = ret;
+ *(buf + buf_row_ring + off + 3) = *(ptr + loc + 3);
+ }
+
+ buf_row_ring += row_stride;
+ buf_row_ring %= buf_len;
+
+ if (j - 1 >= 0) {
+ memcpy((dst + row_stride * (j - 1)), (buf + buf_row_ring), row_stride * sizeof(char));
+ }
+
+ }
+ buf_row_ring += row_stride;
+ buf_row_ring %= buf_len;
+ int second_last_row = row_stride * (height - 2);
+ memcpy((dst + second_last_row), (buf + buf_row_ring), row_stride * sizeof(char));
+
+ // set last row to black
+ int last_row = row_stride * (height - 1);
+ memset((dst + last_row), 0, row_stride * sizeof(char));
+ for (j = 3; j < row_stride; j+=4) {
+ *(dst + last_row + j) = 255; // set alphas
+ }
+ AndroidBitmap_unlockPixels(env, bitmap);
+}
diff --git a/res/values/filtershow_ids.xml b/res/values/filtershow_ids.xml
index 7f7c98bd0..4ccbd960d 100644
--- a/res/values/filtershow_ids.xml
+++ b/res/values/filtershow_ids.xml
@@ -31,4 +31,5 @@
<item type="id" name="sharpenButton" />
<item type="id" name="curvesButtonRGB" />
<item type="id" name="negativeButton" />
+ <item type="id" name="edgeButton" />
</resources>
diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml
index e011396cd..5095e48e1 100644
--- a/res/values/filtershow_strings.xml
+++ b/res/values/filtershow_strings.xml
@@ -135,6 +135,8 @@
<string name="negative">Negative</string>
<!-- Label for having no filters applied to the image [CHAR LIMIT=10] -->
<string name="none" msgid="3601545724573307541">None</string>
+ <!-- Label for the image edges effect (highlights edges in image) [CHAR LIMIT=10] -->
+ <string name="edge">Edges</string>
<!-- Labels for the curves tool -->
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 6275ae62d..a3da0c6be 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -61,6 +61,7 @@ import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
import com.android.gallery3d.filtershow.filters.ImageFilterBwFilter;
import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
+import com.android.gallery3d.filtershow.filters.ImageFilterEdge;
import com.android.gallery3d.filtershow.filters.ImageFilterExposure;
import com.android.gallery3d.filtershow.filters.ImageFilterFx;
import com.android.gallery3d.filtershow.filters.ImageFilterHue;
@@ -309,7 +310,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
new ImageFilterHue(),
new ImageFilterSaturated(),
new ImageFilterBwFilter(),
- new ImageFilterNegative()
+ new ImageFilterNegative(),
+ new ImageFilterEdge()
};
for (int i = 0; i < filters.length; i++) {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
new file mode 100644
index 000000000..e2ce0dacd
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
@@ -0,0 +1,40 @@
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+
+import com.android.gallery3d.R;
+
+public class ImageFilterEdge extends ImageFilter {
+
+ public ImageFilterEdge() {
+ mName = "Edge";
+ mPreviewParameter = 0;
+ }
+
+ native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float p);
+
+ @Override
+ public int getButtonId() {
+ return R.id.edgeButton;
+ }
+
+ @Override
+ public int getTextId() {
+ return R.string.edge;
+ }
+
+ @Override
+ public boolean isNil() {
+ return false;
+ }
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ float p = mParameter + 101;
+ p = (float) p / 100;
+ nativeApplyFilter(bitmap, w, h, p);
+ return bitmap;
+ }
+}