diff options
author | Qiwen Zhao <zhao@google.com> | 2013-08-05 18:37:28 -0700 |
---|---|---|
committer | Qiwen Zhao <zhao@google.com> | 2013-08-05 18:37:28 -0700 |
commit | e426d40137e32e579c70fbcd28fd94e74799f2a9 (patch) | |
tree | 37433cd606a5b41ded9350a824737636d60f4d82 | |
parent | ae49a9f990643202d28e7a5b6f999163914d8246 (diff) | |
parent | 3d5d54874f1c1e0a0f60899a4d7c45c517e087a3 (diff) | |
download | android_packages_apps_Snap-e426d40137e32e579c70fbcd28fd94e74799f2a9.tar.gz android_packages_apps_Snap-e426d40137e32e579c70fbcd28fd94e74799f2a9.tar.bz2 android_packages_apps_Snap-e426d40137e32e579c70fbcd28fd94e74799f2a9.zip |
Merge jni/ from platform/packages/apps/Gallery2 to jni/
-rw-r--r-- | jni/Android.mk | 52 | ||||
-rw-r--r-- | jni/Application.mk | 1 | ||||
-rw-r--r-- | jni/filters/bwfilter.c | 55 | ||||
-rw-r--r-- | jni/filters/contrast.c | 56 | ||||
-rw-r--r-- | jni/filters/edge.c | 126 | ||||
-rw-r--r-- | jni/filters/exposure.c | 37 | ||||
-rw-r--r-- | jni/filters/filters.h | 53 | ||||
-rw-r--r-- | jni/filters/fx.c | 88 | ||||
-rw-r--r-- | jni/filters/geometry.c | 184 | ||||
-rw-r--r-- | jni/filters/gradient.c | 65 | ||||
-rw-r--r-- | jni/filters/highlight.c | 40 | ||||
-rw-r--r-- | jni/filters/hsv.c | 156 | ||||
-rw-r--r-- | jni/filters/hue.c | 46 | ||||
-rw-r--r-- | jni/filters/kmeans.cc | 81 | ||||
-rw-r--r-- | jni/filters/kmeans.h | 232 | ||||
-rw-r--r-- | jni/filters/negative.c | 33 | ||||
-rw-r--r-- | jni/filters/redEyeMath.c | 172 | ||||
-rw-r--r-- | jni/filters/redeye.c | 31 | ||||
-rw-r--r-- | jni/filters/saturated.c | 53 | ||||
-rw-r--r-- | jni/filters/shadows.c | 57 | ||||
-rw-r--r-- | jni/filters/tinyplanet.cc | 150 | ||||
-rw-r--r-- | jni/filters/vibrance.c | 62 | ||||
-rw-r--r-- | jni/filters/vignette.c | 49 | ||||
-rw-r--r-- | jni/filters/wbalance.c | 169 | ||||
-rw-r--r-- | jni/jni_egl_fence.cpp | 78 | ||||
-rw-r--r-- | jni/jni_egl_fence.h | 33 |
26 files changed, 2159 insertions, 0 deletions
diff --git a/jni/Android.mk b/jni/Android.mk new file mode 100644 index 000000000..e612486e1 --- /dev/null +++ b/jni/Android.mk @@ -0,0 +1,52 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES + +LOCAL_SRC_FILES := jni_egl_fence.cpp + +LOCAL_SDK_VERSION := 9 + +LOCAL_LDFLAGS := -llog -lEGL + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE := libjni_eglfence + + +include $(BUILD_SHARED_LIBRARY) + +# Filtershow + +include $(CLEAR_VARS) + +LOCAL_CPP_EXTENSION := .cc +LOCAL_LDFLAGS := -llog -ljnigraphics +LOCAL_SDK_VERSION := 9 +LOCAL_MODULE := libjni_filtershow_filters +LOCAL_SRC_FILES := filters/gradient.c \ + filters/saturated.c \ + filters/exposure.c \ + filters/edge.c \ + filters/contrast.c \ + filters/hue.c \ + filters/shadows.c \ + filters/highlight.c \ + filters/hsv.c \ + filters/vibrance.c \ + filters/geometry.c \ + filters/negative.c \ + filters/vignette.c \ + filters/redEyeMath.c \ + filters/fx.c \ + filters/wbalance.c \ + filters/redeye.c \ + filters/bwfilter.c \ + filters/tinyplanet.cc \ + filters/kmeans.cc + +LOCAL_CFLAGS += -ffast-math -O3 -funroll-loops +LOCAL_ARM_MODE := arm + +include $(BUILD_SHARED_LIBRARY) diff --git a/jni/Application.mk b/jni/Application.mk new file mode 100644 index 000000000..22d188e59 --- /dev/null +++ b/jni/Application.mk @@ -0,0 +1 @@ +APP_PLATFORM := android-9 diff --git a/jni/filters/bwfilter.c b/jni/filters/bwfilter.c new file mode 100644 index 000000000..f7fb31ad1 --- /dev/null +++ b/jni/filters/bwfilter.c @@ -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. + */ + +#include <math.h> +#include "filters.h" + +void JNIFUNCF(ImageFilterBwFilter, nativeApplyFilter, jobject bitmap, jint width, jint height, jint rw, jint gw, jint bw) +{ + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + unsigned char * rgb = (unsigned char * )destination; + float sr = rw; + float sg = gw; + float sb = bw; + + float min = MIN(sg,sb); + min = MIN(sr,min); + float max = MAX(sg,sb); + max = MAX(sr,max); + float avg = (min+max)/2; + sb /= avg; + sg /= avg; + sr /= avg; + int i; + int len = width * height * 4; + + for (i = 0; i < len; i+=4) + { + float r = sr *rgb[RED]; + float g = sg *rgb[GREEN]; + float b = sb *rgb[BLUE]; + min = MIN(g,b); + min = MIN(r,min); + max = MAX(g,b); + max = MAX(r,max); + avg =(min+max)/2; + rgb[RED] = CLAMP(avg); + rgb[GREEN] = rgb[RED]; + rgb[BLUE] = rgb[RED]; + } + AndroidBitmap_unlockPixels(env, bitmap); +} diff --git a/jni/filters/contrast.c b/jni/filters/contrast.c new file mode 100644 index 000000000..b04e9364e --- /dev/null +++ b/jni/filters/contrast.c @@ -0,0 +1,56 @@ +/* + * 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" + +unsigned char clamp(int c) +{ + int N = 255; + c &= ~(c >> 31); + c -= N; + c &= (c >> 31); + c += N; + 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; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + unsigned char * rgb = (unsigned char * )destination; + int i; + int len = width * height * 4; + float m = (float)pow(2, bright/100.); + float c = 127-m*127; + + for (i = 0; i < len; i+=4) { + rgb[RED] = clamp((int)(m*rgb[RED]+c)); + rgb[GREEN] = clamp((int)(m*rgb[GREEN]+c)); + rgb[BLUE] = clamp((int)(m*rgb[BLUE]+c)); + } + AndroidBitmap_unlockPixels(env, bitmap); +} + 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/jni/filters/exposure.c b/jni/filters/exposure.c new file mode 100644 index 000000000..6b32798c8 --- /dev/null +++ b/jni/filters/exposure.c @@ -0,0 +1,37 @@ +/* + * 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 "filters.h" + +void JNIFUNCF(ImageFilterExposure, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat bright) +{ + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + unsigned char * rgb = (unsigned char * )destination; + int i; + int len = width * height * 4; + + int m = (255-bright); + + for (i = 0; i < len; i+=4) + { + rgb[RED] = clamp((255*(rgb[RED]))/m); + rgb[GREEN] = clamp((255*(rgb[GREEN]))/m); + rgb[BLUE] = clamp((255*(rgb[BLUE]))/m); + } + AndroidBitmap_unlockPixels(env, bitmap); +} + diff --git a/jni/filters/filters.h b/jni/filters/filters.h new file mode 100644 index 000000000..14b69cdd4 --- /dev/null +++ b/jni/filters/filters.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef FILTERS_H +#define FILTERS_H + +#include <jni.h> +#include <string.h> +#include <android/log.h> +#include <android/bitmap.h> + +typedef unsigned int Color; + +#define SetColor(a, r, g, b) ((a << 24) | (b << 16) | (g << 8) | (r << 0)); +#define GetA(color) (((color) >> 24) & 0xFF) +#define GetB(color) (((color) >> 16) & 0xFF) +#define GetG(color) (((color) >> 8) & 0xFF) +#define GetR(color) (((color) >> 0) & 0xFF) + +#define MIN(a, b) (a < b ? a : b) +#define MAX(a, b) (a > b ? a : b) + +#define LOG(msg...) __android_log_print(ANDROID_LOG_VERBOSE, "NativeFilters", msg) + +#define JNIFUNCF(cls, name, vars...) Java_com_android_gallery3d_filtershow_filters_ ## cls ## _ ## name(JNIEnv* env, jobject obj, vars) + +#define RED i +#define GREEN i+1 +#define BLUE i+2 +#define ALPHA i+3 +#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); +extern void filterRedEye(unsigned char *src, unsigned char *dest, int iw, int ih, short *rect); +extern double fastevalPoly(double *poly,int n, double x); +#endif // FILTERS_H diff --git a/jni/filters/fx.c b/jni/filters/fx.c new file mode 100644 index 000000000..c3c9cbdc6 --- /dev/null +++ b/jni/filters/fx.c @@ -0,0 +1,88 @@ +/* + * 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 "filters.h" + +__inline__ int interp(unsigned char *src, int p , int *off ,float dr,float dg, float db){ + + float fr00 = (src[p+off[0]])*(1-dr)+(src[p+off[1]])*dr; + float fr01 = (src[p+off[2]])*(1-dr)+(src[p+off[3]])*dr; + float fr10 = (src[p+off[4]])*(1-dr)+(src[p+off[5]])*dr; + float fr11 = (src[p+off[6]])*(1-dr)+(src[p+off[7]])*dr; + float frb0 = fr00 * (1-db)+fr01*db; + float frb1 = fr10 * (1-db)+fr11*db; + float frbg = frb0 * (1-dg)+frb1*dg; + + return (int)frbg ; +} + +void JNIFUNCF(ImageFilterFx, nativeApplyFilter, jobject bitmap, jint width, jint height, + jobject lutbitmap, jint lutwidth, jint lutheight, + jint start, jint end) +{ + char* destination = 0; + char* lut = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + AndroidBitmap_lockPixels(env, lutbitmap, (void**) &lut); + unsigned char * rgb = (unsigned char * )destination; + unsigned char * lutrgb = (unsigned char * )lut; + int lutdim_r = lutheight; + int lutdim_g = lutheight;; + int lutdim_b = lutwidth/lutheight;; + int STEP = 4; + + int off[8] = { + 0, + STEP*1, + STEP*lutdim_r, + STEP*(lutdim_r + 1), + STEP*(lutdim_r*lutdim_b), + STEP*(lutdim_r*lutdim_b+1), + STEP*(lutdim_r*lutdim_b+lutdim_r), + STEP*(lutdim_r*lutdim_b+lutdim_r + 1) + }; + + float scale_R = (lutdim_r-1.f)/256.f; + float scale_G = (lutdim_g-1.f)/256.f; + float scale_B = (lutdim_b-1.f)/256.f; + + int i; + for (i = start; i < end; i+= STEP) + { + int r = rgb[RED]; + int g = rgb[GREEN]; + int b = rgb[BLUE]; + + float fb = b*scale_B; + float fg = g*scale_G; + float fr = r*scale_R; + int lut_b = (int)fb; + int lut_g = (int)fg; + int lut_r = (int)fr; + int p = lut_r+lut_b*lutdim_r+lut_g*lutdim_r*lutdim_b; + p*=STEP; + float dr = fr-lut_r; + float dg = fg-lut_g; + float db = fb-lut_b; + rgb[RED] = clamp(interp(lutrgb,p ,off,dr,dg,db)); + rgb[GREEN] = clamp(interp(lutrgb,p+1,off,dr,dg,db)); + rgb[BLUE] = clamp(interp(lutrgb,p+2,off,dr,dg,db)); + + } + + AndroidBitmap_unlockPixels(env, bitmap); + AndroidBitmap_unlockPixels(env, lutbitmap); +} diff --git a/jni/filters/geometry.c b/jni/filters/geometry.c new file mode 100644 index 000000000..a0b5aaacf --- /dev/null +++ b/jni/filters/geometry.c @@ -0,0 +1,184 @@ +/* + * 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 "filters.h" +#include <stdio.h> + +__inline__ void flipVertical(char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){ + //Vertical + size_t cpy_bytes = sizeof(char) * 4; + int width = cpy_bytes * srcWidth; + int length = srcHeight; + int total = length * width; + size_t bytes_to_copy = sizeof(char) * width; + int i = 0; + int temp = total - width; + for (i = 0; i < total; i += width) { + memcpy(destination + temp - i, source + i, bytes_to_copy); + } +} + +__inline__ void flipHorizontal(char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){ + //Horizontal + size_t cpy_bytes = sizeof(char) * 4; + int width = cpy_bytes * srcWidth; + int length = srcHeight; + int total = length * width; + int i = 0; + int j = 0; + int temp = 0; + for (i = 0; i < total; i+= width) { + temp = width + i - cpy_bytes; + for (j = 0; j < width; j+=cpy_bytes) { + memcpy(destination + temp - j, source + i + j, cpy_bytes); + } + } +} + +__inline__ void flip_fun(int flip, char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){ + int horiz = (flip & 1) != 0; + int vert = (flip & 2) != 0; + if (horiz && vert){ + int arr_len = dstWidth * dstHeight * sizeof(char) * 4; + char* temp = (char *) malloc(arr_len); + flipHorizontal(source, srcWidth, srcHeight, temp, dstWidth, dstHeight); + flipVertical(temp, dstWidth, dstHeight, destination, dstWidth, dstHeight); + free(temp); + return; + } + if (horiz){ + flipHorizontal(source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + return; + } + if (vert){ + flipVertical(source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + return; + } +} + +//90 CCW (opposite of what's used in UI?) +__inline__ void rotate90(char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){ + size_t cpy_bytes = sizeof(char) * 4; + int width = cpy_bytes * srcWidth; + int length = srcHeight; + int total = length * width; + int i = 0; + int j = 0; + for (j = 0; j < length * cpy_bytes; j+= cpy_bytes){ + for (i = 0; i < width; i+=cpy_bytes){ + int column_disp = (width - cpy_bytes - i) * length; + int row_disp = j; + memcpy(destination + column_disp + row_disp , source + j * srcWidth + i, cpy_bytes); + } + } +} + +__inline__ void rotate180(char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){ + flip_fun(3, source, srcWidth, srcHeight, destination, dstWidth, dstHeight); +} + +__inline__ void rotate270(char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){ + rotate90(source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + flip_fun(3, destination, dstWidth, dstHeight, destination, dstWidth, dstHeight); +} + +// rotate == 1 is 90 degrees, 2 is 180, 3 is 270 (positive is CCW). +__inline__ void rotate_fun(int rotate, char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){ + switch( rotate ) + { + case 1: + rotate90(source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + break; + case 2: + rotate180(source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + break; + case 3: + rotate270(source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + break; + default: + break; + } +} + +__inline__ void crop(char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight, int offsetWidth, int offsetHeight){ + size_t cpy_bytes = sizeof(char) * 4; + int row_width = cpy_bytes * srcWidth; + int new_row_width = cpy_bytes * dstWidth; + if ((srcWidth > dstWidth + offsetWidth) || (srcHeight > dstHeight + offsetHeight)){ + return; + } + int i = 0; + int j = 0; + for (j = offsetHeight; j < offsetHeight + dstHeight; j++){ + memcpy(destination + (j - offsetHeight) * new_row_width, source + j * row_width + offsetWidth * cpy_bytes, cpy_bytes * dstWidth ); + } +} + +void JNIFUNCF(ImageFilterGeometry, nativeApplyFilterFlip, jobject src, jint srcWidth, jint srcHeight, jobject dst, jint dstWidth, jint dstHeight, jint flip) { + char* destination = 0; + char* source = 0; + if (srcWidth != dstWidth || srcHeight != dstHeight) { + return; + } + AndroidBitmap_lockPixels(env, src, (void**) &source); + AndroidBitmap_lockPixels(env, dst, (void**) &destination); + flip_fun(flip, source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + AndroidBitmap_unlockPixels(env, dst); + AndroidBitmap_unlockPixels(env, src); +} + +void JNIFUNCF(ImageFilterGeometry, nativeApplyFilterRotate, jobject src, jint srcWidth, jint srcHeight, jobject dst, jint dstWidth, jint dstHeight, jint rotate) { + char* destination = 0; + char* source = 0; + int len = dstWidth * dstHeight * 4; + AndroidBitmap_lockPixels(env, src, (void**) &source); + AndroidBitmap_lockPixels(env, dst, (void**) &destination); + rotate_fun(rotate, source, srcWidth, srcHeight, destination, dstWidth, dstHeight); + AndroidBitmap_unlockPixels(env, dst); + AndroidBitmap_unlockPixels(env, src); +} + +void JNIFUNCF(ImageFilterGeometry, nativeApplyFilterCrop, jobject src, jint srcWidth, jint srcHeight, jobject dst, jint dstWidth, jint dstHeight, jint offsetWidth, jint offsetHeight) { + char* destination = 0; + char* source = 0; + int len = dstWidth * dstHeight * 4; + AndroidBitmap_lockPixels(env, src, (void**) &source); + AndroidBitmap_lockPixels(env, dst, (void**) &destination); + crop(source, srcWidth, srcHeight, destination, dstWidth, dstHeight, offsetWidth, offsetHeight); + AndroidBitmap_unlockPixels(env, dst); + AndroidBitmap_unlockPixels(env, src); +} + +void JNIFUNCF(ImageFilterGeometry, nativeApplyFilterStraighten, jobject src, jint srcWidth, jint srcHeight, jobject dst, jint dstWidth, jint dstHeight, jfloat straightenAngle) { + char* destination = 0; + char* source = 0; + int len = dstWidth * dstHeight * 4; + AndroidBitmap_lockPixels(env, src, (void**) &source); + AndroidBitmap_lockPixels(env, dst, (void**) &destination); + // TODO: implement straighten + int i = 0; + for (; i < len; i += 4) { + int r = source[RED]; + int g = source[GREEN]; + int b = source[BLUE]; + destination[RED] = 128; + destination[GREEN] = g; + destination[BLUE] = 128; + } + AndroidBitmap_unlockPixels(env, dst); + AndroidBitmap_unlockPixels(env, src); +} + diff --git a/jni/filters/gradient.c b/jni/filters/gradient.c new file mode 100644 index 000000000..1a8569786 --- /dev/null +++ b/jni/filters/gradient.c @@ -0,0 +1,65 @@ +/* + * 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 "filters.h" + +void JNIFUNCF(ImageFilter, nativeApplyGradientFilter, jobject bitmap, jint width, jint height, + jintArray redGradient, jintArray greenGradient, jintArray blueGradient) +{ + char* destination = 0; + jint* redGradientArray = 0; + jint* greenGradientArray = 0; + jint* blueGradientArray = 0; + if (redGradient) + redGradientArray = (*env)->GetIntArrayElements(env, redGradient, NULL); + if (greenGradient) + greenGradientArray = (*env)->GetIntArrayElements(env, greenGradient, NULL); + if (blueGradient) + blueGradientArray = (*env)->GetIntArrayElements(env, blueGradient, NULL); + + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + int i; + int len = width * height * 4; + for (i = 0; i < len; i+=4) + { + if (redGradient) + { + int r = destination[RED]; + r = redGradientArray[r]; + destination[RED] = r; + } + if (greenGradient) + { + int g = destination[GREEN]; + g = greenGradientArray[g]; + destination[GREEN] = g; + } + if (blueGradient) + { + int b = destination[BLUE]; + b = blueGradientArray[b]; + destination[BLUE] = b; + } + } + if (redGradient) + (*env)->ReleaseIntArrayElements(env, redGradient, redGradientArray, 0); + if (greenGradient) + (*env)->ReleaseIntArrayElements(env, greenGradient, greenGradientArray, 0); + if (blueGradient) + (*env)->ReleaseIntArrayElements(env, blueGradient, blueGradientArray, 0); + AndroidBitmap_unlockPixels(env, bitmap); +} + 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/jni/filters/hsv.c b/jni/filters/hsv.c new file mode 100644 index 000000000..aabd053fe --- /dev/null +++ b/jni/filters/hsv.c @@ -0,0 +1,156 @@ +/* + * 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" + +double fastevalPoly(double *poly,int n, double x){ + + double f =x; + double sum = poly[0]+poly[1]*f; + int i; + for (i = 2; i < n; i++) { + f*=x; + sum += poly[i]*f; + } + return sum; +} + +void rgb2hsv( unsigned char *rgb,int rgbOff,unsigned short *hsv,int hsvOff) +{ + int iMin,iMax,chroma; + int ABITS = 4; + int HSCALE = 256; + + int k1=255 << ABITS; + int k2=HSCALE << ABITS; + + int ri = rgb[rgbOff+0]; + int gi = rgb[rgbOff+1]; + int bi = rgb[rgbOff+2]; + short rv,rs,rh; + + if (ri > gi) { + iMax = MAX (ri, bi); + iMin = MIN (gi, bi); + } else { + iMax = MAX (gi, bi); + iMin = MIN (ri, bi); + } + + chroma = iMax - iMin; + // set value + rv = (short)( iMax << ABITS); + + // set saturation + if (rv == 0) + rs = 0; + else + rs = (short)((k1*chroma)/iMax); + + // set hue + if (rs == 0) + rh = 0; + else { + if ( ri == iMax ) { + rh = (short)( (k2*(6*chroma+gi - bi))/(6*chroma)); + if (rh >= k2) rh -= k2; + } else if (gi == iMax) + rh = (short)( (k2*(2*chroma+bi - ri ))/(6*chroma)); + else // (bi == iMax ) + rh = (short)( (k2*(4*chroma+ri - gi ))/(6*chroma)); + } + hsv[hsvOff+0] = rv; + hsv[hsvOff+1] = rs; + hsv[hsvOff+2] = rh; +} + +void hsv2rgb(unsigned short *hsv,int hsvOff, unsigned char *rgb,int rgbOff) +{ + int ABITS = 4; + int HSCALE = 256; + int m; + int H,X,ih,is,iv; + int k1=255<<ABITS; + int k2=HSCALE<<ABITS; + int k3=1<<(ABITS-1); + int rr=0; + int rg=0; + int rb=0; + short cv = hsv[hsvOff+0]; + short cs = hsv[hsvOff+1]; + short ch = hsv[hsvOff+2]; + + // set chroma and min component value m + //chroma = ( cv * cs )/k1; + //m = cv - chroma; + m = ((int)cv*(k1 - (int)cs ))/k1; + + // chroma == 0 <-> cs == 0 --> m=cv + if (cs == 0) { + rb = ( rg = ( rr =( cv >> ABITS) )); + } else { + ih=(int)ch; + is=(int)cs; + iv=(int)cv; + + H = (6*ih)/k2; + X = ((iv*is)/k2)*(k2- abs(6*ih- 2*(H>>1)*k2 - k2)) ; + + // removing additional bits --> unit8 + X=( (X+iv*(k1 - is ))/k1 + k3 ) >> ABITS; + m=m >> ABITS; + + // ( chroma + m ) --> cv ; + cv=(short) (cv >> ABITS); + switch (H) { + case 0: + rr = cv; + rg = X; + rb = m; + break; + case 1: + rr = X; + rg = cv; + rb = m; + break; + case 2: + rr = m; + rg = cv; + rb = X; + break; + case 3: + rr = m; + rg = X; + rb = cv; + break; + case 4: + rr = X; + rg = m; + rb = cv; + break; + case 5: + rr = cv; + rg = m ; + rb = X; + break; + } + } + rgb[rgbOff+0] = rr; + rgb[rgbOff+1] = rg; + rgb[rgbOff+2] = rb; +} + diff --git a/jni/filters/hue.c b/jni/filters/hue.c new file mode 100644 index 000000000..a4aef936d --- /dev/null +++ b/jni/filters/hue.c @@ -0,0 +1,46 @@ +/* + * 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 "filters.h" + +void JNIFUNCF(ImageFilterHue, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloatArray matrix) +{ + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + unsigned char * rgb = (unsigned char * )destination; + int i; + int len = width * height * 4; + jfloat* mat = (*env)->GetFloatArrayElements(env, matrix,0); + + for (i = 0; i < len; i+=4) + { + int r = rgb[RED]; + int g = rgb[GREEN]; + int b = rgb[BLUE]; + + float rf = r*mat[0] + g*mat[4] + b*mat[8] + mat[12]; + float gf = r*mat[1] + g*mat[5] + b*mat[9] + mat[13]; + float bf = r*mat[2] + g*mat[6] + b*mat[10] + mat[14]; + + rgb[RED] = clamp((int)rf); + rgb[GREEN] = clamp((int)gf); + rgb[BLUE] = clamp((int)bf); + } + + (*env)->ReleaseFloatArrayElements(env, matrix, mat, 0); + AndroidBitmap_unlockPixels(env, bitmap); +} + diff --git a/jni/filters/kmeans.cc b/jni/filters/kmeans.cc new file mode 100644 index 000000000..97cead7bc --- /dev/null +++ b/jni/filters/kmeans.cc @@ -0,0 +1,81 @@ +/* + * 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 "filters.h" +#include "kmeans.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * For reasonable speeds: + * k < 30 + * small_ds_bitmap width/height < 64 pixels. + * large_ds_bitmap width/height < 512 pixels + * + * bad for high-frequency image noise + */ + +void JNIFUNCF(ImageFilterKMeans, nativeApplyFilter, jobject bitmap, jint width, jint height, + jobject large_ds_bitmap, jint lwidth, jint lheight, jobject small_ds_bitmap, + jint swidth, jint sheight, jint p, jint seed) +{ + char* destination = 0; + char* larger_ds_dst = 0; + char* smaller_ds_dst = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + AndroidBitmap_lockPixels(env, large_ds_bitmap, (void**) &larger_ds_dst); + AndroidBitmap_lockPixels(env, small_ds_bitmap, (void**) &smaller_ds_dst); + unsigned char * dst = (unsigned char *) destination; + + unsigned char * small_ds = (unsigned char *) smaller_ds_dst; + unsigned char * large_ds = (unsigned char *) larger_ds_dst; + + // setting for small bitmap + int len = swidth * sheight * 4; + int dimension = 3; + int stride = 4; + int iterations = 20; + int k = p; + unsigned int s = seed; + unsigned char finalCentroids[k * stride]; + + // get initial picks from small downsampled image + runKMeans<unsigned char, int>(k, finalCentroids, small_ds, len, dimension, + stride, iterations, s); + + + len = lwidth * lheight * 4; + iterations = 8; + unsigned char nextCentroids[k * stride]; + + // run kmeans on large downsampled image + runKMeansWithPicks<unsigned char, int>(k, nextCentroids, large_ds, len, + dimension, stride, iterations, finalCentroids); + + len = width * height * 4; + + // apply to final image + applyCentroids<unsigned char, int>(k, nextCentroids, dst, len, dimension, stride); + + AndroidBitmap_unlockPixels(env, small_ds_bitmap); + AndroidBitmap_unlockPixels(env, large_ds_bitmap); + AndroidBitmap_unlockPixels(env, bitmap); +} +#ifdef __cplusplus +} +#endif diff --git a/jni/filters/kmeans.h b/jni/filters/kmeans.h new file mode 100644 index 000000000..24506058a --- /dev/null +++ b/jni/filters/kmeans.h @@ -0,0 +1,232 @@ +/* + * 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. + */ + +#ifndef KMEANS_H +#define KMEANS_H + +#include <cstdlib> +#include <math.h> + +// Helper functions + +template <typename T, typename N> +inline void sum(T values[], int len, int dimension, int stride, N dst[]) { + int x, y; + // zero out dst vector + for (x = 0; x < dimension; x++) { + dst[x] = 0; + } + for (x = 0; x < len; x+= stride) { + for (y = 0; y < dimension; y++) { + dst[y] += values[x + y]; + } + } +} + +template <typename T, typename N> +inline void set(T val1[], N val2[], int dimension) { + int x; + for (x = 0; x < dimension; x++) { + val1[x] = val2[x]; + } +} + +template <typename T, typename N> +inline void add(T val[], N dst[], int dimension) { + int x; + for (x = 0; x < dimension; x++) { + dst[x] += val[x]; + } +} + +template <typename T, typename N> +inline void divide(T dst[], N divisor, int dimension) { + int x; + if (divisor == 0) { + return; + } + for (x = 0; x < dimension; x++) { + dst[x] /= divisor; + } +} + +/** + * Calculates euclidean distance. + */ + +template <typename T, typename N> +inline N euclideanDist(T val1[], T val2[], int dimension) { + int x; + N sum = 0; + for (x = 0; x < dimension; x++) { + N diff = (N) val1[x] - (N) val2[x]; + sum += diff * diff; + } + return sqrt(sum); +} + +// K-Means + + +/** + * Picks k random starting points from the data set. + */ +template <typename T> +void initialPickHeuristicRandom(int k, T values[], int len, int dimension, int stride, T dst[], + unsigned int seed) { + int x, z, num_vals, cntr; + num_vals = len / stride; + cntr = 0; + srand(seed); + unsigned int r_vals[k]; + unsigned int r; + + for (x = 0; x < k; x++) { + + // ensure randomly chosen value is unique + int r_check = 0; + while (r_check == 0) { + r = (unsigned int) rand() % num_vals; + r_check = 1; + for (z = 0; z < x; z++) { + if (r == r_vals[z]) { + r_check = 0; + } + } + } + r_vals[x] = r; + r *= stride; + + // set dst to be randomly chosen value + set<T,T>(dst + cntr, values + r, dimension); + cntr += stride; + } +} + +/** + * Finds index of closet centroid to a value + */ +template <typename T, typename N> +inline int findClosest(T values[], T oldCenters[], int dimension, int stride, int pop_size) { + int best_ind = 0; + N best_len = euclideanDist <T, N>(values, oldCenters, dimension); + int y; + for (y = stride; y < pop_size; y+=stride) { + N l = euclideanDist <T, N>(values, oldCenters + y, dimension); + if (l < best_len) { + best_len = l; + best_ind = y; + } + } + return best_ind; +} + +/** + * Calculates new centroids by averaging value clusters for old centroids. + */ +template <typename T, typename N> +int calculateNewCentroids(int k, T values[], int len, int dimension, int stride, T oldCenters[], + T dst[]) { + int x, pop_size; + pop_size = k * stride; + int popularities[k]; + N tmp[pop_size]; + + //zero popularities + memset(popularities, 0, sizeof(int) * k); + // zero dst, and tmp + for (x = 0; x < pop_size; x++) { + tmp[x] = 0; + } + + // put summation for each k in tmp + for (x = 0; x < len; x+=stride) { + int best = findClosest<T, N>(values + x, oldCenters, dimension, stride, pop_size); + add<T, N>(values + x, tmp + best, dimension); + popularities[best / stride]++; + + } + + int ret = 0; + int y; + // divide to get centroid and set dst to result + for (x = 0; x < pop_size; x+=stride) { + divide<N, int>(tmp + x, popularities[x / stride], dimension); + for (y = 0; y < dimension; y++) { + if ((dst + x)[y] != (T) ((tmp + x)[y])) { + ret = 1; + } + } + set(dst + x, tmp + x, dimension); + } + return ret; +} + +template <typename T, typename N> +void runKMeansWithPicks(int k, T finalCentroids[], T values[], int len, int dimension, int stride, + int iterations, T initialPicks[]){ + int k_len = k * stride; + int x; + + // zero newCenters + for (x = 0; x < k_len; x++) { + finalCentroids[x] = 0; + } + + T * c1 = initialPicks; + T * c2 = finalCentroids; + T * temp; + int ret = 1; + for (x = 0; x < iterations; x++) { + ret = calculateNewCentroids<T, N>(k, values, len, dimension, stride, c1, c2); + temp = c1; + c1 = c2; + c2 = temp; + if (ret == 0) { + x = iterations; + } + } + set<T, T>(finalCentroids, c1, dimension); +} + +/** + * Runs the k-means algorithm on dataset values with some initial centroids. + */ +template <typename T, typename N> +void runKMeans(int k, T finalCentroids[], T values[], int len, int dimension, int stride, + int iterations, unsigned int seed){ + int k_len = k * stride; + T initialPicks [k_len]; + initialPickHeuristicRandom<T>(k, values, len, dimension, stride, initialPicks, seed); + + runKMeansWithPicks<T, N>(k, finalCentroids, values, len, dimension, stride, + iterations, initialPicks); +} + +/** + * Sets each value in values to the closest centroid. + */ +template <typename T, typename N> +void applyCentroids(int k, T centroids[], T values[], int len, int dimension, int stride) { + int x, pop_size; + pop_size = k * stride; + for (x = 0; x < len; x+= stride) { + int best = findClosest<T, N>(values + x, centroids, dimension, stride, pop_size); + set<T, T>(values + x, centroids + best, dimension); + } +} + +#endif // KMEANS_H diff --git a/jni/filters/negative.c b/jni/filters/negative.c new file mode 100644 index 000000000..735e583c9 --- /dev/null +++ b/jni/filters/negative.c @@ -0,0 +1,33 @@ +/* + * 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 "filters.h" + +void JNIFUNCF(ImageFilterNegative, nativeApplyFilter, jobject bitmap, jint width, jint height) +{ + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + + int tot_len = height * width * 4; + int i; + char * dst = destination; + for (i = 0; i < tot_len; i+=4) { + dst[RED] = 255 - dst[RED]; + dst[GREEN] = 255 - dst[GREEN]; + dst[BLUE] = 255 - dst[BLUE]; + } + AndroidBitmap_unlockPixels(env, bitmap); +} diff --git a/jni/filters/redEyeMath.c b/jni/filters/redEyeMath.c new file mode 100644 index 000000000..26f3f76a4 --- /dev/null +++ b/jni/filters/redEyeMath.c @@ -0,0 +1,172 @@ +/* + * 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" + +int value(int r, int g, int b) { + return MAX(r, MAX(g, b)); +} + +int isRed(unsigned char *src, int p) { + int b = src[p + 2]; + int g = src[p + 1]; + int r = src[p]; + int max = MAX(g, b); + + return ((r * 100 / (max + 2) > 160) & (max < 80)); +} + +void findPossible(unsigned char *src, unsigned char *mask, int iw, int ih, + short *rect) { + int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3]; + int y, x; + + for (y = 0; y < recH; y++) { + int sy = (recY + y) * iw; + for (x = 0; x < recW; x++) { + int p = (recX + x + sy) * 4; + + int b = src[p + 2]; + int g = src[p + 1]; + int r = src[p]; + mask[x + y * recW] = ( + mask[x + y * recW] > 0 && (value(r, g, b) > 240) ? 1 : 0); + + } + + } +} + +void findReds(unsigned char *src, unsigned char *mask, int iw, int ih, + short *rect) { + int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3]; + int y, x; + + for (y = 0; y < recH; y++) { + int sy = (recY + y) * iw; + for (x = 0; x < recW; x++) { + int p = (recX + x + sy) * 4; + + mask[x + y * recW] = ((isRed(src, p)) ? 1 : 0); + + } + + } +} + +void dialateMaskIfRed(unsigned char *src, int iw, int ih, unsigned char *mask, + unsigned char *out, short *rect) { + int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3]; + int y, x; + + for (y = 1; y < recH - 1; y++) { + int row = recW * y; + int sy = (recY + y) * iw; + for (x = 1; x < recW - 1; x++) { + int p = (recX + x + sy) * 4; + + char b = (mask[row + x] | mask[row + x + 1] | mask[row + x - 1] + | mask[row + x - recW] | mask[row + x + recW]); + if (b != 0 && isRed(src, p)) + out[row + x] = 1; + else + out[row + x] = mask[row + x]; + } + } +} + +void dialateMask(unsigned char *mask, unsigned char *out, int mw, int mh) { + int y, x; + for (y = 1; y < mh - 1; y++) { + int row = mw * y; + for (x = 1; x < mw - 1; x++) { + out[row + x] = (mask[row + x] | mask[row + x + 1] + | mask[row + x - 1] | mask[row + x - mw] + | mask[row + x + mw]); + } + } +} + +void stuff(int r, int g, int b, unsigned char *img, int off) { + img[off + 2] = b; + img[off + 1] = g; + img[off] = r; +} + +void filterRedEye(unsigned char *src, unsigned char *dest, int iw, int ih, short *rect) { + int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3]; + unsigned char *mask1 = (unsigned char *) malloc(recW * recH); + unsigned char *mask2 = (unsigned char *)malloc(recW*recH); + int QUE_LEN = 100; + int y, x, i; + + rect[0] = MAX(rect[0],0); + rect[1] = MAX(rect[1],0); + rect[2] = MIN(rect[2]+rect[0],iw)-rect[0]; + rect[3] = MIN(rect[3]+rect[1],ih)-rect[1]; + + findReds(src, mask2, iw, ih, rect); + dialateMask(mask2, mask1, recW, recH); + dialateMask(mask1, mask2, recW, recH); + dialateMask(mask2, mask1, recW, recH); + dialateMask(mask1, mask2, recW, recH); + findPossible(src, mask2, iw, ih, rect); + dialateMask(mask2, mask1, recW, recH); + + for (i = 0; i < 12; i++) { + dialateMaskIfRed(src, iw, ih, mask1, mask2, rect); + dialateMaskIfRed(src, iw, ih, mask2, mask1, rect); + } + dialateMask(mask1, mask2, recW, recH); + dialateMask(mask2, mask1, recW, recH); + + for (y = 3; y < recH-3; y++) { + int sy = (recY + y) * iw; + for (x = 3; x < recW-3; x++) { + int p = (recX + x + sy) * 4; + + int b = src[p + 2]; + int g = src[p + 1]; + int r = src[p]; + + if (mask1[x + y * recW] != 0) { + int m = MAX(g,b); + float rr = (r - m) / (float) m; + if (rr > .7f && g < 60 && b < 60) { + dest[p + 2] = (0); + dest[p + 1] = (0); + dest[p] = (0); + } else { + if (mask2[x + y * recW] != 0) { + stuff(r / 2, g / 2, b / 2, dest, p); + } else + stuff((2 * r) / 3, (2 * g) / 3, (2 * b) / 3, dest, p); + } + + } else + stuff(r, g, b, dest, p); + + //dest[p + 2] = dest[p + 1] =dest[p]=src[p]; + } + + } + + free(mask1); + free(mask2); +} + + diff --git a/jni/filters/redeye.c b/jni/filters/redeye.c new file mode 100644 index 000000000..9a358dd3d --- /dev/null +++ b/jni/filters/redeye.c @@ -0,0 +1,31 @@ +/* + * 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(ImageFilterRedEye, nativeApplyFilter, jobject bitmap, jint width, jint height, jshortArray vrect) + { + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + unsigned char * rgb = (unsigned char * )destination; + short* rect = (*env)->GetShortArrayElements(env, vrect,0); + + filterRedEye(rgb,rgb,width,height,rect); + + (*env)->ReleaseShortArrayElements(env, vrect, rect, 0); + AndroidBitmap_unlockPixels(env, bitmap); + } diff --git a/jni/filters/saturated.c b/jni/filters/saturated.c new file mode 100644 index 000000000..1bc0cc56b --- /dev/null +++ b/jni/filters/saturated.c @@ -0,0 +1,53 @@ +/* + * 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 "filters.h" + +void JNIFUNCF(ImageFilterSaturated, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat saturation) +{ + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + int i; + int len = width * height * 4; + float Rf = 0.2999f; + float Gf = 0.587f; + float Bf = 0.114f; + float S = saturation;; + float MS = 1.0f - S; + float Rt = Rf * MS; + float Gt = Gf * MS; + float Bt = Bf * MS; + float R, G, B; + for (i = 0; i < len; i+=4) + { + int r = destination[RED]; + int g = destination[GREEN]; + int b = destination[BLUE]; + int t = (r + g) / 2; + R = r; + G = g; + B = b; + + float Rc = R * (Rt + S) + G * Gt + B * Bt; + float Gc = R * Rt + G * (Gt + S) + B * Bt; + float Bc = R * Rt + G * Gt + B * (Bt + S); + + destination[RED] = CLAMP(Rc); + destination[GREEN] = CLAMP(Gc); + destination[BLUE] = CLAMP(Bc); + } + AndroidBitmap_unlockPixels(env, bitmap); +} diff --git a/jni/filters/shadows.c b/jni/filters/shadows.c new file mode 100644 index 000000000..38d64c8b5 --- /dev/null +++ b/jni/filters/shadows.c @@ -0,0 +1,57 @@ +/* + * 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(ImageFilterShadows, nativeApplyFilter, jobject bitmap, jint width, jint height, float scale){ + double shadowFilterMap[] = { + -0.00591, 0.0001, + 1.16488, 0.01668, + -0.18027, -0.06791, + -0.12625, 0.09001, + 0.15065, -0.03897 + }; + + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + unsigned char * rgb = (unsigned char * )destination; + int i; + double s = (scale>=0)?scale:scale/5; + int len = width * height * 4; + + double *poly = (double *) malloc(5*sizeof(double)); + for (i = 0; i < 5; i++) { + poly[i] = fastevalPoly(shadowFilterMap+i*2,2 , s); + } + + unsigned short * hsv = (unsigned short *)malloc(3*sizeof(short)); + + for (i = 0; i < len; i+=4) + { + rgb2hsv(rgb,i,hsv,0); + + double v = (fastevalPoly(poly,5,hsv[0]/4080.)*4080); + if (v>4080) v = 4080; + hsv[0] = (unsigned short) ((v>0)?v:0); + + hsv2rgb(hsv,0, rgb,i); + } + + free(poly); + free(hsv); + AndroidBitmap_unlockPixels(env, bitmap); +} diff --git a/jni/filters/tinyplanet.cc b/jni/filters/tinyplanet.cc new file mode 100644 index 000000000..beac0861a --- /dev/null +++ b/jni/filters/tinyplanet.cc @@ -0,0 +1,150 @@ +/* + * 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 "filters.h" +#include <math.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +#define PI_F 3.141592653589f + +class ImageRGBA { + public: + ImageRGBA(unsigned char* image, int width, int height) + : image_(image), width_(width), height_(height) { + width_step_ = width * 4; + } + + int Width() const { + return width_; + } + + int Height() const { + return height_; + } + + // Pixel accessor. + unsigned char* operator()(int x, int y) { + return image_ + y * width_step_ + x * 4; + } + const unsigned char* operator()(int x, int y) const { + return image_ + y * width_step_ + x * 4; + } + + private: + unsigned char* image_; + int width_; + int height_; + int width_step_; +}; + +// Interpolate a pixel in a 3 channel image. +inline void InterpolatePixel(const ImageRGBA &image, float x, float y, + unsigned char* dest) { + // Get pointers and scale factors for the source pixels. + float ax = x - floor(x); + float ay = y - floor(y); + float axn = 1.0f - ax; + float ayn = 1.0f - ay; + const unsigned char *p = image(x, y); + const unsigned char *p2 = image(x, y + 1); + + // Interpolate each image color plane. + dest[0] = static_cast<unsigned char>(axn * ayn * p[0] + ax * ayn * p[4] + + ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); + p++; + p2++; + + dest[1] = static_cast<unsigned char>(axn * ayn * p[0] + ax * ayn * p[4] + + ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); + p++; + p2++; + + dest[2] = static_cast<unsigned char>(axn * ayn * p[0] + ax * ayn * p[4] + + ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); + p++; + p2++; + dest[3] = 0xFF; +} + +// Wrap circular coordinates around the globe +inline float wrap(float value, float dimension) { + return value - (dimension * floor(value/dimension)); +} + +void StereographicProjection(float scale, float angle, unsigned char* input_image, + int input_width, int input_height, + unsigned char* output_image, int output_width, + int output_height) { + ImageRGBA input(input_image, input_width, input_height); + ImageRGBA output(output_image, output_width, output_height); + + const float image_scale = output_width * scale; + + for (int x = 0; x < output_width; x++) { + // Center and scale x + float xf = (x - output_width / 2.0f) / image_scale; + + for (int y = 0; y < output_height; y++) { + // Center and scale y + float yf = (y - output_height / 2.0f) / image_scale; + + // Convert to polar + float r = hypotf(xf, yf); + float theta = angle+atan2(yf, xf); + if (theta>PI_F) theta-=2*PI_F; + + // Project onto plane + float phi = 2 * atan(1 / r); + // (theta stays the same) + + // Map to panorama image + float px = (theta / (2 * PI_F)) * input_width; + float py = (phi / PI_F) * input_height; + + // Wrap around the globe + px = wrap(px, input_width); + py = wrap(py, input_height); + + // Write the interpolated pixel + InterpolatePixel(input, px, py, output(x, y)); + } + } +} + + +void JNIFUNCF(ImageFilterTinyPlanet, nativeApplyFilter, jobject bitmap_in, jint width, jint height, jobject bitmap_out, jint output_size, jfloat scale,jfloat angle) +{ + char* source = 0; + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap_in, (void**) &source); + AndroidBitmap_lockPixels(env, bitmap_out, (void**) &destination); + unsigned char * rgb_in = (unsigned char * )source; + unsigned char * rgb_out = (unsigned char * )destination; + + StereographicProjection(scale,angle, rgb_in, width, height, rgb_out, output_size, output_size); + AndroidBitmap_unlockPixels(env, bitmap_in); + AndroidBitmap_unlockPixels(env, bitmap_out); +} + +#ifdef __cplusplus +} +#endif + + diff --git a/jni/filters/vibrance.c b/jni/filters/vibrance.c new file mode 100644 index 000000000..cb5c536e5 --- /dev/null +++ b/jni/filters/vibrance.c @@ -0,0 +1,62 @@ +/* + * 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(ImageFilterVibrance, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat vibrance) +{ + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + int i; + int len = width * height * 4; + float Rf = 0.2999f; + float Gf = 0.587f; + float Bf = 0.114f; + float Vib = vibrance/100.f; + float S = Vib+1; + float MS = 1.0f - S; + float Rt = Rf * MS; + float Gt = Gf * MS; + float Bt = Bf * MS; + float R, G, B; + for (i = 0; i < len; i+=4) + { + int r = destination[RED]; + int g = destination[GREEN]; + int b = destination[BLUE]; + float red = (r-MAX(g, b))/256.f; + float sx = (float)(Vib/(1+exp(-red*3))); + S = sx+1; + MS = 1.0f - S; + Rt = Rf * MS; + Gt = Gf * MS; + Bt = Bf * MS; + int t = (r + g) / 2; + R = r; + G = g; + B = b; + + float Rc = R * (Rt + S) + G * Gt + B * Bt; + float Gc = R * Rt + G * (Gt + S) + B * Bt; + float Bc = R * Rt + G * Gt + B * (Bt + S); + + destination[RED] = CLAMP(Rc); + destination[GREEN] = CLAMP(Gc); + destination[BLUE] = CLAMP(Bc); + } + AndroidBitmap_unlockPixels(env, bitmap); +} diff --git a/jni/filters/vignette.c b/jni/filters/vignette.c new file mode 100644 index 000000000..b9ee3ff01 --- /dev/null +++ b/jni/filters/vignette.c @@ -0,0 +1,49 @@ +/* + * 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 "filters.h" +#include <math.h> + +static int* gVignetteMap = 0; +static int gVignetteWidth = 0; +static int gVignetteHeight = 0; + +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); + 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) + { + 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); + } + AndroidBitmap_unlockPixels(env, bitmap); +} diff --git a/jni/filters/wbalance.c b/jni/filters/wbalance.c new file mode 100644 index 000000000..2b92b9978 --- /dev/null +++ b/jni/filters/wbalance.c @@ -0,0 +1,169 @@ +/* + * 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 "filters.h" + +void estmateWhite(unsigned char *src, int len, int *wr, int *wb, int *wg){ + + int STEP = 4; + int RANGE = 256; + int *histR = (int *) malloc(256*sizeof(int)); + int *histG = (int *) malloc(256*sizeof(int)); + int *histB = (int *) malloc(256*sizeof(int)); + int i; + for (i = 0; i < 255; i++) { + histR[i] = histG[i] = histB[i] =0; + } + + for (i = 0; i < len; i+=STEP) { + histR[(src[RED])]++; + histG[(src[GREEN])]++; + histB[(src[BLUE])]++; + } + int min_r = -1, min_g = -1,min_b = -1; + int max_r = 0, max_g = 0,max_b = 0; + int sum_r = 0,sum_g=0,sum_b=0; + + for (i = 1; i < RANGE-1; i++) { + int r = histR[i]; + int g = histG[i]; + int b = histB[i]; + sum_r += r; + sum_g += g; + sum_b += b; + + if (r>0){ + if (min_r < 0) min_r = i; + max_r = i; + } + if (g>0){ + if (min_g < 0) min_g = i; + max_g = i; + } + if (b>0){ + if (min_b < 0) min_b = i; + max_b = i; + } + } + + int sum15r = 0,sum15g=0,sum15b=0; + int count15r = 0,count15g=0,count15b=0; + int tmp_r = 0,tmp_g=0,tmp_b=0; + + for (i = RANGE-2; i >0; i--) { + int r = histR[i]; + int g = histG[i]; + int b = histB[i]; + tmp_r += r; + tmp_g += g; + tmp_b += b; + + if ((tmp_r > sum_r/20) && (tmp_r < sum_r/5)) { + sum15r += r*i; + count15r += r; + } + if ((tmp_g > sum_g/20) && (tmp_g < sum_g/5)) { + sum15g += g*i; + count15g += g; + } + if ((tmp_b > sum_b/20) && (tmp_b < sum_b/5)) { + sum15b += b*i; + count15b += b; + } + + } + free(histR); + free(histG); + free(histB); + + if ((count15r>0) && (count15g>0) && (count15b>0) ){ + *wr = sum15r/count15r; + *wb = sum15g/count15g; + *wg = sum15b/count15b; + }else { + *wg = *wb = *wr=255; + } +} + +void estmateWhiteBox(unsigned char *src, int iw, int ih, int x,int y, int *wr, int *wb, int *wg){ + int r; + int g; + int b; + int sum; + int xp,yp; + int bounds = 5; + if (x<0) x = bounds; + if (y<0) y = bounds; + if (x>=(iw-bounds)) x = (iw-bounds-1); + if (y>=(ih-bounds)) y = (ih-bounds-1); + int startx = x - bounds; + int starty = y - bounds; + int endx = x + bounds; + int endy = y + bounds; + + for(yp= starty;yp<endy;yp++) { + for(xp= startx;xp<endx;xp++) { + int i = 4*(xp+yp*iw); + r += src[RED]; + g += src[GREEN]; + b += src[BLUE]; + sum++; + } + } + *wr = r/sum; + *wg = g/sum; + *wb = b/sum; +} + +void JNIFUNCF(ImageFilterWBalance, nativeApplyFilter, jobject bitmap, jint width, jint height, int locX,int locY) +{ + char* destination = 0; + AndroidBitmap_lockPixels(env, bitmap, (void**) &destination); + int i; + int len = width * height * 4; + unsigned char * rgb = (unsigned char * )destination; + int wr; + int wg; + int wb; + + if (locX==-1) + estmateWhite(rgb,len,&wr,&wg,&wb); + else + estmateWhiteBox(rgb, width, height,locX,locY,&wr,&wg,&wb); + + int min = MIN(wr, MIN(wg, wb)); + int max = MAX(wr, MAX(wg, wb)); + float avg = (min+max)/2.f; + float scaleR = avg/wr; + float scaleG = avg/wg; + float scaleB = avg/wb; + + for (i = 0; i < len; i+=4) + { + int r = rgb[RED]; + int g = rgb[GREEN]; + int b = rgb[BLUE]; + + float Rc = r*scaleR; + float Gc = g*scaleG; + float Bc = b*scaleB; + + rgb[RED] = clamp(Rc); + rgb[GREEN] = clamp(Gc); + rgb[BLUE] = clamp(Bc); + } + AndroidBitmap_unlockPixels(env, bitmap); +} diff --git a/jni/jni_egl_fence.cpp b/jni/jni_egl_fence.cpp new file mode 100644 index 000000000..cf15e2f5d --- /dev/null +++ b/jni/jni_egl_fence.cpp @@ -0,0 +1,78 @@ +/* + * 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 "jni_egl_fence.h" + +#include <android/log.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <string.h> + +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR,"egl_fence",__VA_ARGS__) + +typedef EGLSyncKHR EGLAPIENTRY (*TypeEglCreateSyncKHR)(EGLDisplay dpy, + EGLenum type, const EGLint *attrib_list); +typedef EGLBoolean EGLAPIENTRY (*TypeEglDestroySyncKHR)(EGLDisplay dpy, + EGLSyncKHR sync); +typedef EGLint EGLAPIENTRY (*TypeEglClientWaitSyncKHR)(EGLDisplay dpy, + EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +static TypeEglCreateSyncKHR FuncEglCreateSyncKHR = NULL; +static TypeEglClientWaitSyncKHR FuncEglClientWaitSyncKHR = NULL; +static TypeEglDestroySyncKHR FuncEglDestroySyncKHR = NULL; +static bool initialized = false; +static bool egl_khr_fence_sync_supported = false; + +bool IsEglKHRFenceSyncSupported() { + if (!initialized) { + EGLDisplay display = eglGetCurrentDisplay(); + const char* eglExtensions = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS); + if (eglExtensions && strstr(eglExtensions, "EGL_KHR_fence_sync")) { + FuncEglCreateSyncKHR = (TypeEglCreateSyncKHR) eglGetProcAddress("eglCreateSyncKHR"); + FuncEglClientWaitSyncKHR = (TypeEglClientWaitSyncKHR) eglGetProcAddress("eglClientWaitSyncKHR"); + FuncEglDestroySyncKHR = (TypeEglDestroySyncKHR) eglGetProcAddress("eglDestroySyncKHR"); + if (FuncEglCreateSyncKHR != NULL && FuncEglClientWaitSyncKHR != NULL + && FuncEglDestroySyncKHR != NULL) { + egl_khr_fence_sync_supported = true; + } + } + initialized = true; + } + return egl_khr_fence_sync_supported; +} + +void +Java_com_android_gallery3d_photoeditor_FilterStack_nativeEglSetFenceAndWait(JNIEnv* env, + jobject thiz) { + if (!IsEglKHRFenceSyncSupported()) return; + EGLDisplay display = eglGetCurrentDisplay(); + + // Create a egl fence and wait for egl to return it. + // Additional reference on egl fence sync can be found in: + // http://www.khronos.org/registry/vg/extensions/KHR/EGL_KHR_fence_sync.txt + EGLSyncKHR fence = FuncEglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL); + if (fence == EGL_NO_SYNC_KHR) { + return; + } + + EGLint result = FuncEglClientWaitSyncKHR(display, + fence, + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, + EGL_FOREVER_KHR); + if (result == EGL_FALSE) { + ALOGE("EGL FENCE: error waiting for fence: %#x", eglGetError()); + } + FuncEglDestroySyncKHR(display, fence); +} diff --git a/jni/jni_egl_fence.h b/jni/jni_egl_fence.h new file mode 100644 index 000000000..6b2c20ab8 --- /dev/null +++ b/jni/jni_egl_fence.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#ifndef COM_ANDROID_GALLERY3D_PHOTOEDITOR_JNI_EGL_FENSE_H +#define COM_ANDROID_GALLERY3D_PHOTOEDITOR_JNI_EGL_FENSE_H + +#include <jni.h> + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL +Java_com_android_gallery3d_photoeditor_FilterStack_nativeEglSetFenceAndWait(JNIEnv* env, + jobject thiz); +#ifdef __cplusplus +} +#endif + +#endif /* COM_ANDROID_GALLERY3D_PHOTOEDITOR_JNI_EGL_FENSE_H */ |