From: Sascha Haeberling Date: Fri, 19 Oct 2012 22:43:03 +0000 (-0700) Subject: Adds a tiny planet (stereographic projection) image filter. X-Git-Tag: android-x86-7.1-r1~1268^2~133 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=2f879102d630815df64636b8d37e3a7eea8e8b65;p=android-x86%2Fpackages-apps-Gallery2.git 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 --- 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 + + diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index 760532a8b..2cdc22e94 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -238,7 +238,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, R.id.vibranceButton, R.id.contrastButton, R.id.saturationButton, - R.id.shadowRecoveryButton, R.id.wbalanceButton, R.id.hueButton, R.id.exposureButton, @@ -257,13 +256,12 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, }; for (int i = 0; i < filters.length; i++) { - ImageSmallFilter fView = new ImageSmallFilter(this); View v = listColors.findViewById(recastIDs[i]); int pos = listColors.indexOfChild(v); listColors.removeView(v); - filters[i].setParameter(filters[i].getMaxParameter()); + filters[i].setParameter(filters[i].getPreviewParameter()); if(v instanceof ImageButtonTitle) filters[i].setName(((ImageButtonTitle) v).getText()); fView.setImageFilter(filters[i]); @@ -353,7 +351,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, } else if (action.equalsIgnoreCase(TINY_PLANET_ACTION)) { mPanelController.showComponent(findViewById(R.id.tinyplanetButton)); } - } private int getScreenImageSize() { diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java index f63286cd7..21a1dffb5 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java @@ -9,6 +9,7 @@ public class ImageFilter implements Cloneable { protected int mMaxParameter = 100; protected int mMinParameter = -100; + protected int mPreviewParameter = mMaxParameter; protected int mDefaultParameter = 0; protected int mParameter = 0; private ImagePreset mImagePreset; @@ -41,6 +42,7 @@ public class ImageFilter implements Cloneable { filter.mMinParameter = mMinParameter; filter.mImagePreset = mImagePreset; filter.mDefaultParameter = mDefaultParameter; + filter.mPreviewParameter = mPreviewParameter; return filter; } @@ -81,6 +83,14 @@ public class ImageFilter implements Cloneable { } /** + * The parameter value to be used in previews. + * @return parameter value to be used to preview the filter + */ + public int getPreviewParameter(){ + return mPreviewParameter; + } + + /** * The minimum allowed value (inclusive) * @return minimum value allowed as input to this filter */ diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java index e742bb2ea..cba1cd231 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java @@ -2,47 +2,51 @@ package com.android.gallery3d.filtershow.filters; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Align; -import android.util.Log; import com.android.gallery3d.filtershow.presets.ImagePreset; +/** + * An image filter which creates a tiny planet projection. + */ public class ImageFilterTinyPlanet extends ImageFilter { private static final String TAG = ImageFilterTinyPlanet.class.getSimpleName(); public ImageFilterTinyPlanet() { setFilterType(TYPE_TINYPLANET); mName = "TinyPlanet"; + + mMinParameter = 10; + mMaxParameter = 60; + mDefaultParameter = 20; + mPreviewParameter = 20; + mParameter = 20; } + native protected void nativeApplyFilter( + Bitmap bitmapIn, int width, int height, Bitmap bitmapOut, int outSize, float scale); + @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { - Log.d(TAG, "Applying tiny planet."); - String str = "TinyPlanet"; + public Bitmap apply(Bitmap bitmapIn, float scaleFactor, boolean highQuality) { ImagePreset preset = getImagePreset(); if (preset != null) { - if (!preset.isPanoramaSafe()) { - str = "NO TP"; - - } else { + if (preset.isPanoramaSafe()) { + // TODO(haeberling): Get XMPMeta object. Object xmp = preset.getImageLoader().getXmpObject(); - str = "TP got Xmp"; + } else { + // TODO(haeberling): What should we do for: + // !preset.isPanoramaSafe()? } } - int w = bitmap.getWidth(); - int h = bitmap.getHeight(); - - // Print TinyPlanet as text on the image as a placeholder - // TODO(haeberling): Implement the real deal. - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - paint.setColor(Color.RED); - paint.setTextSize((int) (((mParameter + 100) / 200f) * 100)); - paint.setTextAlign(Align.CENTER); - canvas.drawText(str, w / 2, h / 2, paint); - return super.apply(bitmap, scaleFactor, highQuality); + + int w = bitmapIn.getWidth(); + int h = bitmapIn.getHeight(); + int outputSize = Math.min(w, h); + + Bitmap mBitmapOut = Bitmap.createBitmap( + outputSize, outputSize, Bitmap.Config.ARGB_8888); + + // TODO(haeberling): Add the padding back in based on the meta-data. + nativeApplyFilter(bitmapIn, w, h, mBitmapOut, outputSize, mParameter / 100f); + return mBitmapOut; } }