1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <jni.h> 18 #include <math.h> 19 #include <android/bitmap.h> 20 21 #ifdef __cplusplus 22 extern "C" { 23 #endif 24 25 26 #define PI_F 3.141592653589f 27 28 class ImageRGBA { 29 public: 30 ImageRGBA(unsigned char* image, int width, int height) 31 : image_(image), width_(width), height_(height) { 32 width_step_ = width * 4; 33 } 34 35 int Width() const { 36 return width_; 37 } 38 39 int Height() const { 40 return height_; 41 } 42 43 // Pixel accessor. 44 unsigned char* operator()(int x, int y) { 45 return image_ + y * width_step_ + x * 4; 46 } 47 const unsigned char* operator()(int x, int y) const { 48 return image_ + y * width_step_ + x * 4; 49 } 50 51 private: 52 unsigned char* image_; 53 int width_; 54 int height_; 55 int width_step_; 56 }; 57 58 // Interpolate a pixel in a 3 channel image. 59 inline void InterpolatePixel(const ImageRGBA &image, float x, float y, 60 unsigned char* dest) { 61 // Get pointers and scale factors for the source pixels. 62 float ax = x - floor(x); 63 float ay = y - floor(y); 64 float axn = 1.0f - ax; 65 float ayn = 1.0f - ay; 66 const unsigned char *p = image(x, y); 67 const unsigned char *p2 = image(x, y + 1); 68 69 // Interpolate each image color plane. 70 dest[0] = static_cast<unsigned char>(axn * ayn * p[0] + ax * ayn * p[4] + 71 ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); 72 p++; 73 p2++; 74 75 dest[1] = static_cast<unsigned char>(axn * ayn * p[0] + ax * ayn * p[4] + 76 ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); 77 p++; 78 p2++; 79 80 dest[2] = static_cast<unsigned char>(axn * ayn * p[0] + ax * ayn * p[4] + 81 ax * ay * p2[4] + axn * ay * p2[0] + 0.5f); 82 p++; 83 p2++; 84 dest[3] = 0xFF; 85 } 86 87 // Wrap circular coordinates around the globe 88 inline float wrap(float value, float dimension) { 89 return value - (dimension * floor(value/dimension)); 90 } 91 92 void StereographicProjection(float scale, float angle, unsigned char* input_image, 93 int input_width, int input_height, 94 unsigned char* output_image, int output_width, 95 int output_height) { 96 ImageRGBA input(input_image, input_width, input_height); 97 ImageRGBA output(output_image, output_width, output_height); 98 99 const float image_scale = output_width * scale; 100 101 for (int x = 0; x < output_width; x++) { 102 // Center and scale x 103 float xf = (x - output_width / 2.0f) / image_scale; 104 105 for (int y = 0; y < output_height; y++) { 106 // Center and scale y 107 float yf = (y - output_height / 2.0f) / image_scale; 108 109 // Convert to polar 110 float r = hypotf(xf, yf); 111 float theta = angle+atan2(yf, xf); 112 if (theta>PI_F) theta-=2*PI_F; 113 114 // Project onto plane 115 float phi = 2 * atan(1 / r); 116 // (theta stays the same) 117 118 // Map to panorama image 119 float px = (theta / (2 * PI_F)) * input_width; 120 float py = (phi / PI_F) * input_height; 121 122 // Wrap around the globe 123 px = wrap(px, input_width); 124 py = wrap(py, input_height); 125 126 // Write the interpolated pixel 127 InterpolatePixel(input, px, py, output(x, y)); 128 } 129 } 130 } 131 132 133 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) 134 { 135 char* source = 0; 136 char* destination = 0; 137 AndroidBitmap_lockPixels(env, bitmap_in, (void**) &source); 138 AndroidBitmap_lockPixels(env, bitmap_out, (void**) &destination); 139 unsigned char * rgb_in = (unsigned char * )source; 140 unsigned char * rgb_out = (unsigned char * )destination; 141 142 StereographicProjection(scale, angle, rgb_in, width, height, rgb_out, output_size, output_size); 143 AndroidBitmap_unlockPixels(env, bitmap_in); 144 AndroidBitmap_unlockPixels(env, bitmap_out); 145 } 146 147 #ifdef __cplusplus 148 } 149 #endif 150 151 152