From a6f29e1b7ac87c930b6dbbd1f6e73fefa08bd8fa Mon Sep 17 00:00:00 2001 From: Sascha Haeberling Date: Fri, 19 Oct 2012 15:43:03 -0700 Subject: Adds a tiny planet (stereographic projection) image filter. Bug: 7293391 Also fixes an issue where the preview value was statically set to 100. This adds a preview parameter value that can be set for this purpose. Change-Id: I68c4ec04e86ab8a29ef7f561e5f21a298003677e --- jni/Android.mk | 4 +- jni/filters/filters.h | 2 +- jni/filters/tinyplanet.cc | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 jni/filters/tinyplanet.cc (limited to 'jni') diff --git a/jni/Android.mk b/jni/Android.mk index 85e867ab4..fb8ba86ec 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -21,6 +21,7 @@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) +LOCAL_CPP_EXTENSION := .cc LOCAL_LDFLAGS := -llog -ljnigraphics LOCAL_SDK_VERSION := 9 LOCAL_MODULE := libjni_filtershow_filters @@ -38,7 +39,8 @@ LOCAL_SRC_FILES := filters/bw.c \ filters/redEyeMath.c \ filters/fx.c \ filters/wbalance.c \ - filters/redeye.c + filters/redeye.c \ + filters/tinyplanet.cc LOCAL_CFLAGS += -ffast-math -O3 -funroll-loops LOCAL_ARM_MODE := arm diff --git a/jni/filters/filters.h b/jni/filters/filters.h index d8728f0d4..d518b6398 100644 --- a/jni/filters/filters.h +++ b/jni/filters/filters.h @@ -35,7 +35,7 @@ typedef unsigned int Color; #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 this, vars) +#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 diff --git a/jni/filters/tinyplanet.cc b/jni/filters/tinyplanet.cc new file mode 100644 index 000000000..bc12c32f1 --- /dev/null +++ b/jni/filters/tinyplanet.cc @@ -0,0 +1,148 @@ +/* + * 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 + +#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(axn * ayn * p[0] + ax * ayn * p[4] + + ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); + p++; + p2++; + + dest[1] = static_cast(axn * ayn * p[0] + ax * ayn * p[4] + + ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); + p++; + p2++; + + dest[2] = static_cast(axn * ayn * p[0] + ax * ayn * p[4] + + ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); + p++; + p2++; +} + +// Wrap circular coordinates around the globe +inline float wrap(float value, float dimension) { + return value - (dimension * floor(value/dimension)); +} + +void StereographicProjection(float scale, 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 = atan2(yf, xf); + + // 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) +{ + 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, rgb_in, width, height, rgb_out, output_size, output_size); + AndroidBitmap_unlockPixels(env, bitmap_in); + AndroidBitmap_unlockPixels(env, bitmap_out); +} + +#ifdef __cplusplus +} +#endif + + -- cgit v1.2.3