summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Hoford <hoford@google.com>2013-02-20 17:50:42 -0800
committerJohn Hoford <hoford@google.com>2013-02-21 11:24:47 -0800
commit8921c28c7333ad2b4d34f013904ad4737044f366 (patch)
tree6fd8a763bae0fd3c72ff78a1fc46a3b9e1451db6
parent91b80b2560e663b15ee75ab1bca775028c7868c0 (diff)
downloadandroid_packages_apps_Gallery2-8921c28c7333ad2b4d34f013904ad4737044f366.tar.gz
android_packages_apps_Gallery2-8921c28c7333ad2b4d34f013904ad4737044f366.tar.bz2
android_packages_apps_Gallery2-8921c28c7333ad2b4d34f013904ad4737044f366.zip
add highlight filter
Change-Id: I2e59e09fbc80172b9dfe27b3ce8ff2f1e24c5872
-rw-r--r--jni/Android.mk1
-rw-r--r--jni/filters/contrast.c9
-rw-r--r--jni/filters/filters.h1
-rw-r--r--jni/filters/highlight.c40
-rw-r--r--res/values/filtershow_ids.xml1
-rw-r--r--res/values/filtershow_strings.xml2
-rw-r--r--src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java2
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java73
-rw-r--r--src/com/android/gallery3d/filtershow/filters/SplineMath.java166
9 files changed, 295 insertions, 0 deletions
diff --git a/jni/Android.mk b/jni/Android.mk
index 1843c77ea..e612486e1 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -32,6 +32,7 @@ LOCAL_SRC_FILES := filters/gradient.c \
filters/contrast.c \
filters/hue.c \
filters/shadows.c \
+ filters/highlight.c \
filters/hsv.c \
filters/vibrance.c \
filters/geometry.c \
diff --git a/jni/filters/contrast.c b/jni/filters/contrast.c
index 6c1b976cf..b04e9364e 100644
--- a/jni/filters/contrast.c
+++ b/jni/filters/contrast.c
@@ -27,6 +27,15 @@ unsigned char clamp(int c)
return (unsigned char) c;
}
+int clampMax(int c,int max)
+{
+ c &= ~(c >> 31);
+ c -= max;
+ c &= (c >> 31);
+ c += max;
+ return c;
+}
+
void JNIFUNCF(ImageFilterContrast, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat bright)
{
char* destination = 0;
diff --git a/jni/filters/filters.h b/jni/filters/filters.h
index d518b6398..14b69cdd4 100644
--- a/jni/filters/filters.h
+++ b/jni/filters/filters.h
@@ -44,6 +44,7 @@ typedef unsigned int Color;
#define CLAMP(c) (MAX(0, MIN(255, c)))
__inline__ unsigned char clamp(int c);
+__inline__ int clampMax(int c,int max);
extern void rgb2hsv( unsigned char *rgb,int rgbOff,unsigned short *hsv,int hsvOff);
extern void hsv2rgb(unsigned short *hsv,int hsvOff,unsigned char *rgb,int rgbOff);
diff --git a/jni/filters/highlight.c b/jni/filters/highlight.c
new file mode 100644
index 000000000..fe9b88f94
--- /dev/null
+++ b/jni/filters/highlight.c
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include <math.h>
+#include "filters.h"
+
+void JNIFUNCF(ImageFilterHighlights, nativeApplyFilter, jobject bitmap,
+ jint width, jint height, jfloatArray luminanceMap){
+ char* destination = 0;
+ AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
+ unsigned char * rgb = (unsigned char * )destination;
+ int i;
+ int len = width * height * 4;
+ jfloat* lum = (*env)->GetFloatArrayElements(env, luminanceMap,0);
+ unsigned short * hsv = (unsigned short *)malloc(3*sizeof(short));
+
+ for (i = 0; i < len; i+=4)
+ {
+ rgb2hsv(rgb,i,hsv,0);
+ int v = clampMax(hsv[0],4080);
+ hsv[0] = (unsigned short) clampMax(lum[((255*v)/4080)]*4080,4080);
+ hsv2rgb(hsv,0, rgb,i);
+ }
+
+ free(hsv);
+ AndroidBitmap_unlockPixels(env, bitmap);
+}
diff --git a/res/values/filtershow_ids.xml b/res/values/filtershow_ids.xml
index ba318345b..28e78166d 100644
--- a/res/values/filtershow_ids.xml
+++ b/res/values/filtershow_ids.xml
@@ -28,6 +28,7 @@
<item type="id" name="hueButton" />
<item type="id" name="exposureButton" />
<item type="id" name="shadowRecoveryButton" />
+ <item type="id" name="highlightRecoveryButton" />
<item type="id" name="sharpenButton" />
<item type="id" name="curvesButtonRGB" />
<item type="id" name="negativeButton" />
diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml
index 66fb3902d..a845c3482 100644
--- a/res/values/filtershow_strings.xml
+++ b/res/values/filtershow_strings.xml
@@ -115,6 +115,8 @@
<string name="hue">Hue</string>
<!-- Label for the image shadow recovery (lightens/darkens shadows) filter button [CHAR LIMIT=10] -->
<string name="shadow_recovery">Shadows</string>
+ <!-- Label for the image highlights recovery (lightens/darkens bright regions) filter button [CHAR LIMIT=15] -->
+ <string name="highlight_recovery">Highlights</string>
<!-- Label for the image curves filter button [CHAR LIMIT=10] -->
<string name="curvesRGB">Curves</string>
<!-- Label for the image vignette filter (darkens photo around edges) button [CHAR LIMIT=10] -->
diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
index 43660d6a0..377bd2b6f 100644
--- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
+++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
@@ -42,6 +42,7 @@ public class BaseFiltersManager {
filters.add(new ImageFilterVignette());
filters.add(new ImageFilterContrast());
filters.add(new ImageFilterShadows());
+ filters.add(new ImageFilterHighlights());
filters.add(new ImageFilterVibrance());
filters.add(new ImageFilterSharpen());
filters.add(new ImageFilterCurves());
@@ -89,6 +90,7 @@ public class BaseFiltersManager {
representations.add(getRepresentation(ImageFilterVignette.class));
representations.add(getRepresentation(ImageFilterContrast.class));
representations.add(getRepresentation(ImageFilterShadows.class));
+ representations.add(getRepresentation(ImageFilterHighlights.class));
representations.add(getRepresentation(ImageFilterVibrance.class));
representations.add(getRepresentation(ImageFilterSharpen.class));
representations.add(getRepresentation(ImageFilterCurves.class));
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java
new file mode 100644
index 000000000..b9a14652a
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import com.android.gallery3d.R;
+
+import android.graphics.Bitmap;
+import android.util.Log;
+
+public class ImageFilterHighlights extends SimpleImageFilter {
+ private static final String LOGTAG = "ImageFilterVignette";
+
+ public ImageFilterHighlights() {
+ mName = "Highlights";
+ }
+
+ SplineMath mSpline = new SplineMath(5);
+ double[] mHighlightCurve = { 0.0, 0.32, 0.418, 0.476, 0.642 };
+
+ public FilterRepresentation getDefaultRepresentation() {
+ FilterBasicRepresentation representation =
+ (FilterBasicRepresentation) super.getDefaultRepresentation();
+ representation.setName("Shadows");
+ representation.setFilterClass(ImageFilterHighlights.class);
+ representation.setTextId(R.string.highlight_recovery);
+ representation.setButtonId(R.id.highlightRecoveryButton);
+ representation.setMinimum(-100);
+ representation.setMaximum(100);
+ representation.setDefaultValue(0);
+ return representation;
+ }
+
+ native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float[] luminanceMap);
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
+ if (getParameters() == null) {
+ return bitmap;
+ }
+ float p = getParameters().getValue();
+ double t = p/100.;
+ for (int i = 0; i < 5; i++) {
+ double x = i / 4.;
+ double y = mHighlightCurve[i] *t+x*(1-t);
+ mSpline.setPoint(i, x, y);
+ }
+
+ float[][] curve = mSpline.calculatetCurve(256);
+ float[] luminanceMap = new float[curve.length];
+ for (int i = 0; i < luminanceMap.length; i++) {
+ luminanceMap[i] = curve[i][1];
+ }
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+
+ nativeApplyFilter(bitmap, w, h, luminanceMap);
+ return bitmap;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/SplineMath.java b/src/com/android/gallery3d/filtershow/filters/SplineMath.java
new file mode 100644
index 000000000..5b12d0a61
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/SplineMath.java
@@ -0,0 +1,166 @@
+package com.android.gallery3d.filtershow.filters;
+
+
+public class SplineMath {
+ double[][] mPoints = new double[6][2];
+ double[] mDerivatives;
+ SplineMath(int n) {
+ mPoints = new double[n][2];
+ }
+
+ public void setPoint(int index, double x, double y) {
+ mPoints[index][0] = x;
+ mPoints[index][1] = y;
+ mDerivatives = null;
+ }
+
+ public float[][] calculatetCurve(int n) {
+ float[][] curve = new float[n][2];
+ double[][] points = new double[mPoints.length][2];
+ for (int i = 0; i < mPoints.length; i++) {
+
+ points[i][0] = mPoints[i][0];
+ points[i][1] = mPoints[i][1];
+
+ }
+ double[] derivatives = solveSystem(points);
+ float start = (float) points[0][0];
+ float end = (float) (points[points.length - 1][0]);
+
+ curve[0][0] = (float) (points[0][0]);
+ curve[0][1] = (float) (points[0][1]);
+ int last = curve.length - 1;
+ curve[last][0] = (float) (points[points.length - 1][0]);
+ curve[last][1] = (float) (points[points.length - 1][1]);
+
+ for (int i = 0; i < curve.length; i++) {
+
+ double[] cur = null;
+ double[] next = null;
+ double x = start + i * (end - start) / (curve.length - 1);
+ int pivot = 0;
+ for (int j = 0; j < points.length - 1; j++) {
+ if (x >= points[j][0] && x <= points[j + 1][0]) {
+ pivot = j;
+ }
+ }
+ cur = points[pivot];
+ next = points[pivot + 1];
+ if (x <= next[0]) {
+ double x1 = cur[0];
+ double x2 = next[0];
+ double y1 = cur[1];
+ double y2 = next[1];
+
+ // Use the second derivatives to apply the cubic spline
+ // equation:
+ double delta = (x2 - x1);
+ double delta2 = delta * delta;
+ double b = (x - x1) / delta;
+ double a = 1 - b;
+ double ta = a * y1;
+ double tb = b * y2;
+ double tc = (a * a * a - a) * derivatives[pivot];
+ double td = (b * b * b - b) * derivatives[pivot + 1];
+ double y = ta + tb + (delta2 / 6) * (tc + td);
+
+ curve[i][0] = (float) (x);
+ curve[i][1] = (float) (y);
+ } else {
+ curve[i][0] = (float) (next[0]);
+ curve[i][1] = (float) (next[1]);
+ }
+ }
+ return curve;
+ }
+
+ public double getValue(double x) {
+ double[] cur = null;
+ double[] next = null;
+ if (mDerivatives == null)
+ mDerivatives = solveSystem(mPoints);
+ int pivot = 0;
+ for (int j = 0; j < mPoints.length - 1; j++) {
+ pivot = j;
+ if (x <= mPoints[j][0]) {
+ break;
+ }
+ }
+ cur = mPoints[pivot];
+ next = mPoints[pivot + 1];
+ double x1 = cur[0];
+ double x2 = next[0];
+ double y1 = cur[1];
+ double y2 = next[1];
+
+ // Use the second derivatives to apply the cubic spline
+ // equation:
+ double delta = (x2 - x1);
+ double delta2 = delta * delta;
+ double b = (x - x1) / delta;
+ double a = 1 - b;
+ double ta = a * y1;
+ double tb = b * y2;
+ double tc = (a * a * a - a) * mDerivatives[pivot];
+ double td = (b * b * b - b) * mDerivatives[pivot + 1];
+ double y = ta + tb + (delta2 / 6) * (tc + td);
+
+ return y;
+
+ }
+
+ double[] solveSystem(double[][] points) {
+ int n = points.length;
+ double[][] system = new double[n][3];
+ double[] result = new double[n]; // d
+ double[] solution = new double[n]; // returned coefficients
+ system[0][1] = 1;
+ system[n - 1][1] = 1;
+ double d6 = 1.0 / 6.0;
+ double d3 = 1.0 / 3.0;
+
+ // let's create a tridiagonal matrix representing the
+ // system, and apply the TDMA algorithm to solve it
+ // (see http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm)
+ for (int i = 1; i < n - 1; i++) {
+ double deltaPrevX = points[i][0] - points[i - 1][0];
+ double deltaX = points[i + 1][0] - points[i - 1][0];
+ double deltaNextX = points[i + 1][0] - points[i][0];
+ double deltaNextY = points[i + 1][1] - points[i][1];
+ double deltaPrevY = points[i][1] - points[i - 1][1];
+ system[i][0] = d6 * deltaPrevX; // a_i
+ system[i][1] = d3 * deltaX; // b_i
+ system[i][2] = d6 * deltaNextX; // c_i
+ result[i] = (deltaNextY / deltaNextX) - (deltaPrevY / deltaPrevX); // d_i
+ }
+
+ // Forward sweep
+ for (int i = 1; i < n; i++) {
+ // m = a_i/b_i-1
+ double m = system[i][0] / system[i - 1][1];
+ // b_i = b_i - m(c_i-1)
+ system[i][1] = system[i][1] - m * system[i - 1][2];
+ // d_i = d_i - m(d_i-1)
+ result[i] = result[i] - m * result[i - 1];
+ }
+
+ // Back substitution
+ solution[n - 1] = result[n - 1] / system[n - 1][1];
+ for (int i = n - 2; i >= 0; --i) {
+ solution[i] = (result[i] - system[i][2] * solution[i + 1]) / system[i][1];
+ }
+ return solution;
+ }
+
+ public static void main(String[] args) {
+ SplineMath s = new SplineMath(10);
+ for (int i = 0; i < 10; i++) {
+ s.setPoint(i, i, i);
+ }
+ float[][] curve = s.calculatetCurve(40);
+
+ for (int j = 0; j < curve.length; j++) {
+ System.out.println(curve[j][0] + "," + curve[j][1]);
+ }
+ }
+}