From a5a08d7642a1fdf961b057cc90e76c4c93103c15 Mon Sep 17 00:00:00 2001 From: Sascha Haeberling Date: Wed, 11 Sep 2013 20:30:52 -0700 Subject: Bring back tiny planet to the Camera filmstrip Bug: 10393598 The native code and XmpUtil are mostly 1:1 copies from Gallery2. The UI is new and should work on all form factors. Change-Id: Ia302a4a7a24cf0b3aa583836683c459e9e7e1f85 --- Android.mk | 4 +- jni/Android.mk | 15 + jni/tinyplanet.cc | 151 +++++++ res/layout/tinyplanet_editor.xml | 73 ++++ res/values/strings.xml | 10 + src/com/android/camera/CameraActivity.java | 92 ++-- src/com/android/camera/MediaSaveService.java | 2 +- .../camera/tinyplanet/TinyPlanetFragment.java | 475 +++++++++++++++++++++ .../camera/tinyplanet/TinyPlanetNative.java | 42 ++ .../camera/tinyplanet/TinyPlanetPreview.java | 117 +++++ src/com/android/camera/ui/FilmStripView.java | 6 +- src/com/android/camera/util/XmpUtil.java | 405 ++++++++++++++++++ 12 files changed, 1360 insertions(+), 32 deletions(-) create mode 100644 jni/tinyplanet.cc create mode 100644 res/layout/tinyplanet_editor.xml create mode 100644 src/com/android/camera/tinyplanet/TinyPlanetFragment.java create mode 100644 src/com/android/camera/tinyplanet/TinyPlanetNative.java create mode 100644 src/com/android/camera/tinyplanet/TinyPlanetPreview.java create mode 100644 src/com/android/camera/util/XmpUtil.java diff --git a/Android.mk b/Android.mk index ef4772844..285e59543 100644 --- a/Android.mk +++ b/Android.mk @@ -30,9 +30,9 @@ LOCAL_PROGUARD_FLAG_FILES := proguard.flags # the libraries in the APK, otherwise just put them in /system/lib and # leave them out of the APK ifneq (,$(TARGET_BUILD_APPS)) - LOCAL_JNI_SHARED_LIBRARIES := libjni_mosaic + LOCAL_JNI_SHARED_LIBRARIES := libjni_mosaic libjni_tinyplanet else - LOCAL_REQUIRED_MODULES := libjni_mosaic + LOCAL_REQUIRED_MODULES := libjni_mosaic libjni_tinyplanet endif include $(BUILD_PACKAGE) diff --git a/jni/Android.mk b/jni/Android.mk index 9f6f73925..b9bafcf6c 100755 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -58,3 +58,18 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libjni_mosaic include $(BUILD_SHARED_LIBRARY) + +# TinyPlanet +include $(CLEAR_VARS) + +LOCAL_CPP_EXTENSION := .cc +LOCAL_LDFLAGS := -llog -ljnigraphics +LOCAL_SDK_VERSION := 9 +LOCAL_MODULE := libjni_tinyplanet +LOCAL_SRC_FILES := tinyplanet.cc + +LOCAL_CFLAGS += -ffast-math -O3 -funroll-loops +LOCAL_ARM_MODE := arm + +include $(BUILD_SHARED_LIBRARY) + diff --git a/jni/tinyplanet.cc b/jni/tinyplanet.cc new file mode 100644 index 000000000..dfb31d768 --- /dev/null +++ b/jni/tinyplanet.cc @@ -0,0 +1,151 @@ +/* + * 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 +#include +#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++; + 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)); + } + } +} + + +JNIEXPORT void JNICALL Java_com_android_camera_tinyplanet_TinyPlanetNative_process(JNIEnv* env, jobject obj, 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/res/layout/tinyplanet_editor.xml b/res/layout/tinyplanet_editor.xml new file mode 100644 index 000000000..8880c2cfb --- /dev/null +++ b/res/layout/tinyplanet_editor.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + +