diff options
-rw-r--r-- | jni/Android.mk | 1 | ||||
-rw-r--r-- | jni/filters/edge.c | 126 | ||||
-rw-r--r-- | res/values/filtershow_ids.xml | 1 | ||||
-rw-r--r-- | res/values/filtershow_strings.xml | 2 | ||||
-rw-r--r-- | src/com/android/gallery3d/filtershow/FilterShowActivity.java | 4 | ||||
-rw-r--r-- | src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java | 40 |
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; + } +} |