diff options
author | Andrew Hsieh <andrewhsieh@google.com> | 2011-07-22 11:24:17 -0700 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2011-07-22 11:24:17 -0700 |
commit | 0f8a40e4cfdc5f6cd47c22e81f69ed0446067c54 (patch) | |
tree | 6f25f7ed29d5314f4161f5ad1f7df91a81d78a20 | |
parent | b2080cd3e724758f3437c210c04d65a413ea7f15 (diff) | |
download | gdk-0f8a40e4cfdc5f6cd47c22e81f69ed0446067c54.tar.gz |
Adding PhotoEditor & quake res/; Misc fixes
Change-Id: I3d96725b2c6c96eabddc484a62a1919ac20814be
252 files changed, 14008 insertions, 1 deletions
diff --git a/platforms/android-portable/arch-llvm/usr/README b/platforms/android-portable/arch-llvm/usr/README new file mode 100644 index 0000000..f634f09 --- /dev/null +++ b/platforms/android-portable/arch-llvm/usr/README @@ -0,0 +1,5 @@ +This file is a placeholder that reminds us +this directory should put the portable headers. +Currently a link is poinitng to ndk/platform + +This README should be removed in future. diff --git a/platforms/android-portable/arch-llvm/usr/include b/platforms/android-portable/arch-llvm/usr/include new file mode 120000 index 0000000..914bdcf --- /dev/null +++ b/platforms/android-portable/arch-llvm/usr/include @@ -0,0 +1 @@ +../../../../../ndk/platforms/android-9/arch-arm/usr/include
\ No newline at end of file diff --git a/samples/PhotoEditor/Android.mk b/samples/PhotoEditor/Android.mk new file mode 100644 index 0000000..87acd60 --- /dev/null +++ b/samples/PhotoEditor/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := PhotoEditor + +LOCAL_JNI_SHARED_LIBRARIES := libjni_photoeditor + +LOCAL_REQUIRED_MODULES := libjni_photoeditor + +LOCAL_SDK_VERSION := 11 + +include $(BUILD_PACKAGE) + +ifeq ($(strip $(LOCAL_PACKAGE_OVERRIDES)),) +include $(call all-makefiles-under, $(LOCAL_PATH)) +endif diff --git a/samples/PhotoEditor/AndroidManifest.xml b/samples/PhotoEditor/AndroidManifest.xml new file mode 100644 index 0000000..f70bbd6 --- /dev/null +++ b/samples/PhotoEditor/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> + +<manifest package="com.android.photoeditor" + android:versionCode="10001" + android:versionName="1.0.001" xmlns:android="http://schemas.android.com/apk/res/android"> + + <original-package android:name="com.android.photoeditor" /> + + <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="11" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + + <application + android:icon="@drawable/icon" + android:label="@string/app_name" + android:largeHeap="true" + android:hardwareAccelerated="true"> + <activity android:name=".PhotoEditor" + android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" + android:clearTaskOnLaunch="true" + android:configChanges="orientation" + android:screenOrientation="landscape"> + <intent-filter> + <action android:name="android.intent.action.EDIT" /> + <data android:mimeType="image/*" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/samples/PhotoEditor/jni/Android-portable.mk b/samples/PhotoEditor/jni/Android-portable.mk new file mode 100644 index 0000000..861ff01 --- /dev/null +++ b/samples/PhotoEditor/jni/Android-portable.mk @@ -0,0 +1,46 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +#LOCAL_SHARED_LIBRARIES := libm liblog libjnigraphics +#LOCAL_LDLIBS := -lm -llog -ljnigraphics -lbcc + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE := libjni_photoeditor_portable + +LOCAL_SRC_FILES := _jni.cpp \ + utils.cpp \ + backlight.cpp \ + blur.cpp \ + colortemp.cpp \ + convolution.cpp \ + copy.cpp \ + crossprocess.cpp \ + duotone.cpp \ + fisheye.cpp \ + flip.cpp \ + grain.cpp \ + grayscale.cpp \ + heq.cpp \ + negative.cpp \ + quantize.cpp \ + redeye.cpp \ + saturate.cpp \ + sepia.cpp \ + sharpen.cpp \ + tint.cpp \ + vignetting.cpp \ + warmify.cpp \ + whiteblack.cpp + +# This doesn't work on non-ARM yet. +ifeq ($(TARGET_ARCH), arm) + LOCAL_NDK_VERSION := 5 + LOCAL_SDK_VERSION := 9 +endif + +LOCAL_C_INCLUDES := $(OUT)/../../../../frameworks/compile/libbcc/include +#LOCAL_LDFLAGS := -L$(OUT)/system/lib + +include $(BUILD_BITCODE) diff --git a/samples/PhotoEditor/jni/Android.mk b/samples/PhotoEditor/jni/Android.mk new file mode 100644 index 0000000..c94794a --- /dev/null +++ b/samples/PhotoEditor/jni/Android.mk @@ -0,0 +1,49 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +#LOCAL_SHARED_LIBRARIES := libm liblog libjnigraphics +LOCAL_LDLIBS := -lm -llog -ljnigraphics -lbcc + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE := libjni_photoeditor + +LOCAL_SRC_FILES := _jni.cpp \ + utils.cpp \ + backlight.cpp \ + blur.cpp \ + colortemp.cpp \ + convolution.cpp \ + copy.cpp \ + crossprocess.cpp \ + duotone.cpp \ + fisheye.cpp \ + flip.cpp \ + grain.cpp \ + grayscale.cpp \ + heq.cpp \ + negative.cpp \ + quantize.cpp \ + redeye.cpp \ + saturate.cpp \ + sepia.cpp \ + sharpen.cpp \ + tint.cpp \ + vignetting.cpp \ + warmify.cpp \ + whiteblack.cpp + +# This doesn't work on non-ARM yet. +ifeq ($(TARGET_ARCH), arm) + LOCAL_NDK_VERSION := 5 + LOCAL_SDK_VERSION := 9 +endif + +LOCAL_CFLAGS := -Werror \ + -I$(OUT)/../../../../frameworks/compile/libbcc/include \ + -I$(OUT)/../../../../dalvik/libnativehelper/include + +LOCAL_LDFLAGS := -L$(OUT)/system/lib + +include $(BUILD_SHARED_LIBRARY) diff --git a/samples/PhotoEditor/jni/Application.mk b/samples/PhotoEditor/jni/Application.mk new file mode 100644 index 0000000..f05229c --- /dev/null +++ b/samples/PhotoEditor/jni/Application.mk @@ -0,0 +1 @@ +APP_ABI := armeabi armeabi-v7a diff --git a/samples/PhotoEditor/jni/_jni.cpp b/samples/PhotoEditor/jni/_jni.cpp new file mode 100644 index 0000000..87263ff --- /dev/null +++ b/samples/PhotoEditor/jni/_jni.cpp @@ -0,0 +1,87 @@ +#if !defined(__clang__) + +#include <nativehelper/jni.h> +#include <android/log.h> +#include <bcc/bcc.h> +#include <dlfcn.h> + + +#define LOG_TAG "libjni_photoeditor" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) + +#include "_jni.h" + +#define DEFINE(f) { #f, 0 }, +JNIFuncType JNIFunc[JNI_max] = +{ +#include "_jnif.h" +}; +#undef DEFINE + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + LOGI("JNI_OnLoad\n"); + +#define DEFINE(f) JNIFunc[ JNI_ ## f ].func_ptr = (void *)f; + #include "_jnif.h" +#undef DEFINE + + return JNI_VERSION_1_4; +} + +static void* lookupSymbol(void* pContext, const char* name) +{ + return (void*) dlsym(RTLD_DEFAULT, name); +} + +extern "C" JNIEXPORT jboolean JNICALL Java_com_android_photoeditor_filters_ImageUtils_init( + JNIEnv *env, jobject obj, jbyteArray scriptRef, jint length) +{ + void *new_func_ptr[JNI_max]; + int i, all_func_found = 1; + + BCCScriptRef script_ref = bccCreateScript(); + jbyte* script_ptr = (jbyte *)env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0); + LOGI("BCC Script Len: %d", length); + if (bccReadBC(script_ref, "libjni_photoeditor_portable.bc", (const char*)script_ptr, length, 0)) { + LOGE("Error! Cannot bccReadBc"); + return JNI_FALSE; + } + if (script_ptr) { + env->ReleasePrimitiveArrayCritical(scriptRef, script_ptr, 0); + } + #if 0 + if (bccLinkFile(script_ref, "/system/lib/libclcore.bc", 0)) { + LOGE("Error! Cannot bccLinkBC"); + return JNI_FALSE; + } + #endif + bccRegisterSymbolCallback(script_ref, lookupSymbol, NULL); + if (bccPrepareExecutableEx(script_ref, ".", "/data/data/com.android.photoeditor/photoeditorLLVM", 0)) { + LOGE("Error! Cannot bccPrepareExecutableEx"); + return JNI_FALSE; + } + for(i=0; i<JNI_max; i++) { + new_func_ptr[i] = bccGetFuncAddr(script_ref, JNIFunc[i].func_name); + if (new_func_ptr[i] == NULL) { + LOGE("Error! Cannot find %s()\n", JNIFunc[i].func_name); + all_func_found = 0; + //return JNI_FALSE; + } else + LOGI("Found %s() @ 0x%x", JNIFunc[i].func_name, (unsigned)new_func_ptr[i]); + } + + //bccDisposeScript(script_ref); + + if (all_func_found) + { + LOGI("Use LLVM version"); + for(i=0; i<JNI_max; i++) + JNIFunc[i].func_ptr = new_func_ptr[i]; + } + + return JNI_TRUE; +} + +#endif // __clang__
\ No newline at end of file diff --git a/samples/PhotoEditor/jni/_jni.h b/samples/PhotoEditor/jni/_jni.h new file mode 100644 index 0000000..b806a15 --- /dev/null +++ b/samples/PhotoEditor/jni/_jni.h @@ -0,0 +1,69 @@ +extern "C" +{ + void Backlight(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat backlight); + void Blur(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); + void ColorTemp(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); + void Copy(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void CrossProcess(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void Duotone(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint color1, jint color2); + void Fisheye(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat focus_x, jfloat focus_y, jfloat scale); + void FlipHorizontal(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void FlipVertical(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void FlipBoth(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void Grain(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat noise_scale); + void Grayscale(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); + void HEQ(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); + void Negative(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void Quantize(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void RedEye(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jobjectArray redeye_positions, jfloat radius, jfloat intensity); + void Saturation(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); + void Sepia(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void Sharpen(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); + void Tint(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint tint); + void Vignetting(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat range); + void Warmify(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); + void WhiteBlack(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat white, jfloat black); +}; + +typedef void (*pBacklightType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat backlight); +typedef void (*pBlurType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); +typedef void (*pColorTempType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); +typedef void (*pCopyType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pCrossProcessType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pDuotoneType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint color1, jint color2); +typedef void (*pFisheyeType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat focus_x, jfloat focus_y, jfloat scale); +typedef void (*pFlipHorizontalType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pFlipVerticalType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pFlipBothType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pGrainType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat noise_scale); +typedef void (*pGrayscaleType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); +typedef void (*pHEQType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); +typedef void (*pNegativeType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pQuantizeType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pRedEyeType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jobjectArray redeye_positions, jfloat radius, jfloat intensity); +typedef void (*pSaturationType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); +typedef void (*pSepiaType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pSharpenType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale); +typedef void (*pTintType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint tint); +typedef void (*pVignettingType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat range); +typedef void (*pWarmifyType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap); +typedef void (*pWhiteBlackType)(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat white, jfloat black); + +#define DEFINE(f) JNI_ ## f, +enum +{ +#include "_jnif.h" + JNI_max +}; +#undef DEFINE + + +typedef struct +{ + const char *func_name; + void *func_ptr; +} JNIFuncType; + +extern JNIFuncType JNIFunc[JNI_max]; + + diff --git a/samples/PhotoEditor/jni/_jnif.h b/samples/PhotoEditor/jni/_jnif.h new file mode 100644 index 0000000..da3bf51 --- /dev/null +++ b/samples/PhotoEditor/jni/_jnif.h @@ -0,0 +1,23 @@ +DEFINE(Backlight) +DEFINE(Blur) +DEFINE(ColorTemp) +DEFINE(Copy) +DEFINE(CrossProcess) +DEFINE(Duotone) +DEFINE(Fisheye) +DEFINE(FlipHorizontal) +DEFINE(FlipVertical) +DEFINE(FlipBoth) +DEFINE(Grain) +DEFINE(Grayscale) +DEFINE(HEQ) +DEFINE(Negative) +DEFINE(Quantize) +DEFINE(RedEye) +DEFINE(Saturation) +DEFINE(Sepia) +DEFINE(Sharpen) +DEFINE(Tint) +DEFINE(Vignetting) +DEFINE(Warmify) +DEFINE(WhiteBlack) diff --git a/samples/PhotoEditor/jni/backlight.cpp b/samples/PhotoEditor/jni/backlight.cpp new file mode 100644 index 0000000..7beeecb --- /dev/null +++ b/samples/PhotoEditor/jni/backlight.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeBacklight( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat backlight) { + pBacklightType f = (pBacklightType)JNIFunc[JNI_Backlight].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, backlight); +} + +extern "C" void Backlight(JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat backlight) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Backlight failed, error=%d", ret); + return; + } + + const float fade_gamma = 0.3f; + const float amt = 1.0f - backlight; + const float mult = 1.0f / (amt * 0.7f + 0.3f); + const float faded = fade_gamma + (1.0f - fade_gamma) * mult; + const float igamma = 1.0f / faded; + + int lookup[256]; + for (int i = 0; i < 256; i++) { + float value = static_cast<float>(pow(mult * i / 255.0f, igamma)); + if (value > 256.0f) { + value = 256.0f; + } + lookup[i] = floor(255.0f * value) - i; + } + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + while (src < src_line_end) { + int32_t src_red = src->rgba8[0]; + int32_t src_green = src->rgba8[1]; + int32_t src_blue = src->rgba8[2]; + int32_t src_alpha = src->rgba8[3]; + + int32_t lightmask = (src_red + src_green * 2 + src_blue) >> 2; + int32_t backmask = 256 * (255 - lightmask); + + int32_t diff_red = lookup[src_red] * backmask; + int32_t diff_green = lookup[src_green] * backmask; + int32_t diff_blue = lookup[src_blue] * backmask; + + int32_t dst_red = src_red + (diff_red >> 16); + int32_t dst_green = src_green + (diff_green >> 16); + int32_t dst_blue = src_blue + (diff_blue >> 16); + + if (dst_red > 255) { + dst_red = 255; + } + if (dst_green > 255) { + dst_green = 255; + } + if (dst_blue > 255) { + dst_blue = 255; + } + + *dst = (src_alpha << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/blur.cpp b/samples/PhotoEditor/jni/blur.cpp new file mode 100644 index 0000000..1888c35 --- /dev/null +++ b/samples/PhotoEditor/jni/blur.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "convolution.h" +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::convolution::SpecialConvolution; +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeBlur( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + pBlurType f = (pBlurType)JNIFunc[JNI_Blur].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, scale); +} + +extern "C" void Blur( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Sharpen failed, error=%d", ret); + return; + } + + /* Divide blur scale by a factor of 5 which comes from trials. Due to a small (3x3) + * kernel is used for convolution, small blur factor causes double edge. */ + SpecialConvolution(&src_info, &dst_info, src_pixels, dst_pixels, scale / 5); + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/colortemp.cpp b/samples/PhotoEditor/jni/colortemp.cpp new file mode 100644 index 0000000..07a9049 --- /dev/null +++ b/samples/PhotoEditor/jni/colortemp.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +const int k256Multiply255 = 65280; + +/* + * @param scale ranges from -0.5 to 0.5. + */ +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeColorTemp( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + pColorTempType f = (pColorTempType)JNIFunc[JNI_ColorTemp].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, scale); +} + +extern "C" void ColorTemp( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in ColorTemp failed, error=%d", ret); + return; + } + + int curve[256]; + for (int i = 0; i < 256; i++) { + curve[i] = i * (256 - i); + } + + int ics = static_cast<int>(scale * 256); + int icsr = ics; + int icsg = ics > 0 ? ics : 0; + int icsb = ics; + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + int32_t src_red = src->rgba8[0]; + int32_t src_green = src->rgba8[1]; + int32_t src_blue = src->rgba8[2]; + int32_t src_alpha = src->rgba8[3]; + + int32_t dst_red = src_red + ((curve[src_red] * icsr) >> 15); + int32_t dst_green = src_green + ((curve[src_green] * icsg) >> 17); + int32_t dst_blue = src_blue - ((curve[src_blue] * icsb) >> 15); + + int rgb_max = MAX3(dst_red, dst_green, dst_blue); + if (rgb_max > 255) { + int invmax = k256Multiply255 / rgb_max; + dst_red = dst_red * invmax >> 8; + dst_green = dst_green * invmax >> 8; + dst_blue = dst_blue * invmax >> 8; + } + + *dst = (src_alpha << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/convolution.cpp b/samples/PhotoEditor/jni/convolution.cpp new file mode 100644 index 0000000..9be537a --- /dev/null +++ b/samples/PhotoEditor/jni/convolution.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> + +#include <cstdlib> + +#include "utils.h" + +using android::apps::photoeditor::utils::clamp; +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace android { +namespace apps { +namespace photoeditor { +namespace convolution { + +/* + * Used for convolution of following kernel: + * n n n + * n c n + * n n n + * n: neighbor, c: center + */ +void SpecialConvolution(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, + void *src_pixels, void *dst_pixels, float neighbor) { + + if (neighbor == 0) { + memcpy(dst_pixels, src_pixels, src_info->stride * src_info->height); + return; + } + + /* Copy the first row to dst_pixels */ + memcpy(dst_pixels, src_pixels, src_info->stride); + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride; + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride; + + const int32_t kShiftBits = 10; + int32_t fixed_neighbor = static_cast<int32_t>((1 << kShiftBits) * neighbor); + int32_t fixed_center = static_cast<int32_t>((1 << kShiftBits) * (1 - neighbor * 8)); + + for (uint32_t scan_line = 1; scan_line < dst_info->height - 1; scan_line++) { + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + uint32_t* src_prev = reinterpret_cast<uint32_t*> + (reinterpret_cast<char*>(src_pixels) - src_info->stride); + uint32_t* src_next = reinterpret_cast<uint32_t*> + (reinterpret_cast<char*>(src_pixels) + src_info->stride); + + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + *dst++ = src->rgba32; + src++; + src_prev++; + src_next++; + + uint32_t* dst_line_end = dst + dst_info->width - 1; + while (dst < dst_line_end) { + int32_t src_red = src->rgba8[0]; + int32_t src_green = src->rgba8[1]; + int32_t src_blue = src->rgba8[2]; + int32_t src_alpha = src->rgba8[3]; + + uint8_t* n1 = reinterpret_cast<uint8_t*>(src_prev - 1); + uint8_t* n2 = reinterpret_cast<uint8_t*>(src - 1); + uint8_t* n3 = reinterpret_cast<uint8_t*>(src_next - 1); + uint8_t* n4 = reinterpret_cast<uint8_t*>(src_prev); + uint8_t* n5 = reinterpret_cast<uint8_t*>(src_next); + uint8_t* n6 = reinterpret_cast<uint8_t*>(src_prev + 1); + uint8_t* n7 = reinterpret_cast<uint8_t*>(src + 1); + uint8_t* n8 = reinterpret_cast<uint8_t*>(src_next + 1); + + int32_t red = n1[0] + n2[0] + n3[0] + n4[0] + n5[0] + n6[0] + n7[0] + n8[0]; + int32_t green = n1[1] + n2[1] + n3[1] + n4[1] + n5[1] + n6[1] + n7[1] + n8[1]; + int32_t blue = n1[2] + n2[2] + n3[2] + n4[2] + n5[2] + n6[2] + n7[2] + n8[2]; + + red = (fixed_neighbor * red + fixed_center * src_red) >> kShiftBits; + green = (fixed_neighbor * green + fixed_center * src_green) >> kShiftBits; + blue = (fixed_neighbor * blue + fixed_center * src_blue) >> kShiftBits; + + red = clamp(red, 0, 255); + green = clamp(green, 0, 255); + blue = clamp(blue, 0, 255); + + *dst = (src_alpha << 24) | (blue << 16) | (green << 8) | red; + dst++; + src++; + src_prev++; + src_next++; + } + *dst = src->rgba32; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride; + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride; + } + + /* Copy the last row to dst_pixels */ + memcpy(dst_pixels, src_pixels, src_info->stride); +} + +} // namespace convolution +} // namespace photoeditor +} // namespace apps +} // namespace android diff --git a/samples/PhotoEditor/jni/convolution.h b/samples/PhotoEditor/jni/convolution.h new file mode 100644 index 0000000..fd6d5f2 --- /dev/null +++ b/samples/PhotoEditor/jni/convolution.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 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 PHOTOEDITOR_JNI_CONVOLUTION_H_ +#define PHOTOEDITOR_JNI_CONVOLUTION_H_ + +#include <android/bitmap.h> + +namespace android { +namespace apps { +namespace photoeditor { +namespace convolution { + +void SpecialConvolution(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, + void *src_pixels, void *dst_pixels, float neighbor); + +} // namespace convolution +} // namespace photoeditor +} // namespace apps +} // namespace android + +#endif // PHOTOEDITOR_JNI_CONVOLUTION_H_ diff --git a/samples/PhotoEditor/jni/copy.cpp b/samples/PhotoEditor/jni/copy.cpp new file mode 100644 index 0000000..01707de --- /dev/null +++ b/samples/PhotoEditor/jni/copy.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cstdlib> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeCopy( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pCopyType f = (pCopyType)JNIFunc[JNI_Copy].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void Copy( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Copy failed, error=%d", ret); + return; + } + + memcpy(dst_pixels, src_pixels, src_info.stride * src_info.height); + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/crossprocess.cpp b/samples/PhotoEditor/jni/crossprocess.cpp new file mode 100644 index 0000000..e150693 --- /dev/null +++ b/samples/PhotoEditor/jni/crossprocess.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeCrossProcess( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pCrossProcessType f = (pCrossProcessType)JNIFunc[JNI_CrossProcess].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void CrossProcess( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Crossprocess failed, error=%d", ret); + return; + } + + const int k128SquareDouble = 32768; // 2 * 128^2 + const int k128CubicDouble = 4194304; // 2 * 128^3 + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + // Enhance red contrast + uint32_t r = src->rgba8[0]; + uint32_t dst_red; + if (r <= 128) { + dst_red = 255 * r * r * r / k128CubicDouble; + } else { + uint32_t diff_r = 255 - r; + dst_red = 255 - 255 * diff_r * diff_r * diff_r / k128CubicDouble; + } + // Enhance green contrast + int g = src->rgba8[1]; + uint32_t dst_green; + if (g <= 128) { + dst_green = 255 * g * g / k128SquareDouble; + } else { + int diff_g = 255 - g; + dst_green = 255 - 255 * diff_g * diff_g / k128SquareDouble; + } + // Narrow the blue channel, from 64 to 192. + int dst_blue = src->rgba8[2] * 128 / 255 + 64; + + *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/duotone.cpp b/samples/PhotoEditor/jni/duotone.cpp new file mode 100644 index 0000000..daae4de --- /dev/null +++ b/samples/PhotoEditor/jni/duotone.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeDuotone( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint color1, jint color2) { + pDuotoneType f = (pDuotoneType)JNIFunc[JNI_Duotone].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, color1, color2); +} + +extern "C" void Duotone( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint color1, jint color2) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Duotone failed, error=%d", ret); + return; + } + + uint8_t red1 = static_cast<uint8_t>(color1 >> 16) & 0xff; + uint8_t green1 = static_cast<uint8_t>(color1 >> 8) & 0xff; + uint8_t blue1 = static_cast<uint8_t>(color1) & 0xff; + + uint8_t red2 = (uint8_t)(color2 >> 16) & 0xff; + uint8_t green2 = (uint8_t)(color2 >> 8) & 0xff; + uint8_t blue2 = (uint8_t)color2 & 0xff; + + int r_delta = red2 - red1; + int g_delta = green2 - green1; + int b_delta = blue2 - blue1; + + const uint32_t kEnergyLevels = 255 * 3 + 1; + uint8_t r_table[kEnergyLevels]; + uint8_t g_table[kEnergyLevels]; + uint8_t b_table[kEnergyLevels]; + for (uint32_t energy = 0; energy < kEnergyLevels; energy++) { + r_table[energy] = (uint8_t)(red1 + energy * r_delta / kEnergyLevels); + g_table[energy] = (uint8_t)(green1 + energy * g_delta / kEnergyLevels); + b_table[energy] = (uint8_t)(blue1 + energy * b_delta / kEnergyLevels); + } + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + uint32_t energy = src->rgba8[0] + src->rgba8[1] + src->rgba8[2]; + + int dst_red = r_table[energy]; + int dst_green = g_table[energy]; + int dst_blue = b_table[energy]; + + *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/fisheye.cpp b/samples/PhotoEditor/jni/fisheye.cpp new file mode 100644 index 0000000..5e26a3a --- /dev/null +++ b/samples/PhotoEditor/jni/fisheye.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> +#include <cstdlib> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +uint32_t BilinearPixelInterpolation( + float x, float y, uint8_t *p00, uint8_t *p01, uint8_t *p10, uint8_t *p11) { + + float coef4 = x * y; + float coef2 = x - coef4; // x * (1 - y) + float coef3 = y - coef4; // (1 - x) * y + float coef1 = 1 - x - coef3; // (1 - x) * (1 - y) + + int dst_red = p00[0] * coef1 + p10[0] * coef2 + p01[0] * coef3 + p11[0] * coef4; + int dst_green = p00[1] * coef1 + p10[1] * coef2 + p01[1] * coef3 + p11[1] * coef4; + int dst_blue = p00[2] * coef1 + p10[2] * coef2 + p01[2] * coef3 + p11[2] * coef4; + if (dst_red > 255) { + dst_red = 255; + } + if (dst_green > 255) { + dst_green = 255; + } + if (dst_blue > 255) { + dst_blue = 255; + } + + // alpha is not calculated, directly from any point should do. + return p00[3] << 24 | (dst_blue << 16) | (dst_green << 8) | dst_red; +} + +void FisheyeMapPixels( + float px, float py, uint32_t x, uint32_t y, AndroidBitmapInfo *src_info, + AndroidBitmapInfo *dst_info, void *src_pixels, void *dst_pixels) { + if (x >= src_info->width || y >= src_info->height) { + return; + } + + uint32_t px_floor = floor(px); + uint32_t py_floor = floor(py); + + uint32_t *p00 = (uint32_t*)((char*)src_pixels + src_info->stride * py_floor) + px_floor; + uint32_t *p01, *p10, *p11; + if (py_floor + 1 < src_info->height) { + p01 = (uint32_t*)((char*)p00 + src_info->stride); + } else { + p01 = p00; + } + if (py_floor + 1 < src_info->width) { + p10 = p00 + 1; + p11 = p01 + 1; + } else { + p10 = p00; + p11 = p01; + } + + uint32_t *dst = (uint32_t*)((char*)dst_pixels + dst_info->stride * y) + x; + *dst = BilinearPixelInterpolation(px - px_floor, py - py_floor, + (uint8_t*)p00, (uint8_t*)p01, (uint8_t*)p10, (uint8_t*)p11); +} + +/* + * @param scale ranges from 0.0 to 1.0. + * @param focus_x is the X-coord of the center of the projection ranging from 0 to 1. + * @param focus_y is the Y-coord of the center of the projection ranging from 0 to 1. + */ +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeFisheye( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, + jfloat focus_x, jfloat focus_y, jfloat scale) { + pFisheyeType f = (pFisheyeType)JNIFunc[JNI_Fisheye].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, focus_x, focus_y, scale); +} + +extern "C" void Fisheye( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, + jfloat focus_x, jfloat focus_y, jfloat scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in FishEye failed, error=%d", ret); + return; + } + + if (scale == 0) { + memcpy(dst_pixels, src_pixels, src_info.stride * src_info.height); + return; + } + + float far_point = hypotf(src_info.height * focus_y, src_info.width * focus_x); + const float r = far_point * 1.15; // radius + const float r2 = r * r; + const uint32_t center_x = round(src_info.width * focus_x); + const uint32_t center_y = round(src_info.height * focus_y); + float alpha = 0.75 + scale * 2.0; + float linear_scale = far_point / + (M_PI_2 - atan(alpha * sqrtf(r2 - far_point * far_point) / far_point)); + + for (uint32_t scan_line = 0; scan_line <= center_y; scan_line++) { + + int y = scan_line - center_y; + int y2 = y * y; + + for (uint32_t dst_x = 0; dst_x <= center_x; dst_x++) { + int x = dst_x - center_x; + float xy2 = (x * x + y2); + float s_xy2 = sqrtf(xy2); + float r_scale = linear_scale * (M_PI_2 - atan(alpha * sqrtf(r2 - xy2) / s_xy2)) / s_xy2; + float scaled_x = x * r_scale; + float scaled_y = y * r_scale; + int nx = center_x - x; + int ny = center_y - y; + float fpx = center_x + scaled_x; + float fnx = center_x - scaled_x; + float fpy = center_y + scaled_y; + float fny = center_y - scaled_y; + + FisheyeMapPixels(fpx, fpy, dst_x, scan_line, &src_info, &dst_info, src_pixels, dst_pixels); + FisheyeMapPixels(fpx, fny, dst_x, ny, &src_info, &dst_info, src_pixels, dst_pixels); + FisheyeMapPixels(fnx, fpy, nx, scan_line, &src_info, &dst_info, src_pixels, dst_pixels); + FisheyeMapPixels(fnx, fny, nx, ny, &src_info, &dst_info, src_pixels, dst_pixels); + } + } + // Deal with the condition when x = 0 and y = 0 (dst_x = center_x and + // scan_line = center_y. + uint32_t *dst = (uint32_t*)((char*)dst_pixels + dst_info.stride * center_y) + center_x; + *dst = *((uint32_t*)((char*)src_pixels + src_info.stride * center_y) + center_x); + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/flip.cpp b/samples/PhotoEditor/jni/flip.cpp new file mode 100644 index 0000000..cdeb6d9 --- /dev/null +++ b/samples/PhotoEditor/jni/flip.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeFlipHorizontal( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pFlipHorizontalType f = (pFlipHorizontalType)JNIFunc[JNI_FlipHorizontal].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void FlipHorizontal( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in FlipHorizontal failed, error=%d", ret); + return; + } + + for (uint32_t scan_line = 0; scan_line < src_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels) + src_info.width - 1; + uint32_t* src = reinterpret_cast<uint32_t*>(src_pixels); + uint32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + *dst = *src; + src++; + dst--; + } + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeFlipVertical( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pFlipVerticalType f = (pFlipVerticalType)JNIFunc[JNI_FlipVertical].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void FlipVertical( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in FlipVertical failed, error=%d", ret); + return; + } + + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride * (dst_info.height - 1); + for (uint32_t scan_line = 0; scan_line < src_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + uint32_t* src = reinterpret_cast<uint32_t*>(src_pixels); + uint32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + *dst = *src; + src++; + dst++; + } + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + dst_pixels = reinterpret_cast<char*>(dst_pixels) - dst_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeFlipBoth( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pFlipBothType f = (pFlipBothType)JNIFunc[JNI_FlipBoth].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void FlipBoth( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in FlipBoth failed, error=%d", ret); + return; + } + + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride * (dst_info.height - 1); + for (uint32_t scan_line = 0; scan_line < src_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels) + src_info.width - 1; + uint32_t* src = reinterpret_cast<uint32_t*>(src_pixels); + uint32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + *dst = *src; + src++; + dst--; + } + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + dst_pixels = reinterpret_cast<char*>(dst_pixels) - dst_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/grain.cpp b/samples/PhotoEditor/jni/grain.cpp new file mode 100644 index 0000000..b051660 --- /dev/null +++ b/samples/PhotoEditor/jni/grain.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> +#include <cstdlib> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +const uint32_t kShiftBits = 10; +const uint32_t kShiftValue = (1 << kShiftBits); + +/* + * Convolution matrix of distance 2 with fixed point of 'kShiftBits' bits + * shifted. Thus the sum of this matrix should be 'kShiftValue'. Entries of + * small values are not calculated to gain efficiency. + * The order ot pixels represented in this matrix is: + * 1 2 3 + * 4 0 5 + * 6 7 8 + * and the matrix should be: {230, 56, 114, 56, 114, 114, 56, 114, 56}. + * However, since most of the valus are identical, we only use the first three + * entries and the entries corresponding to the pixels is: + * 1 2 1 + * 2 0 2 + * 1 2 1 + */ +const uint32_t convolution_matrix[3] = {230, 56, 114}; + +/* + * Generate a blurred random noise bitmap. + */ +void GenerateBlurredNoise(void* dst_pixels, AndroidBitmapInfo* dst_info, + float noise_scale) { + uint32_t fixed_noise_scale = noise_scale * kShiftValue; + + // Clear dst bitmap to 0 for storing generated random noise. + memset(dst_pixels, 0, dst_info->stride * dst_info->height); + + // 0.5 is a empirical value and could be tuned. + int random_threshold = RAND_MAX * 0.5; + for (uint32_t y = 0; y < dst_info->height; y++) { + uint32_t* dp_line = reinterpret_cast<uint32_t*>( + reinterpret_cast<char*>(dst_pixels) + y * dst_info->stride); + + for (uint32_t x = 0; x < dst_info->width; x++) { + if (rand() < random_threshold) { + uint32_t* dp = dp_line + x; + uint32_t* dp_prev = (y == 0) ? dp : (dp - dst_info->width); + uint32_t* dp_next = (y == dst_info->height - 1) ? dp : (dp + dst_info->width); + + /* + * 1 2 3 + * 4 0 5 + * 6 7 8 + */ + uint32_t* n[9]; + n[0] = dp; + n[2] = dp_prev; + n[7] = dp_next; + if (x == 0) { + n[1] = n[2]; + n[4] = n[0]; + n[6] = n[7]; + } else { + n[1] = n[2] - 1; + n[4] = n[0] - 1; + n[6] = n[7] - 1; + } + if (x == dst_info->width - 1) { + n[3] = n[2]; + n[5] = n[0]; + n[8] = n[7]; + } else { + n[3] = n[2] + 1; + n[5] = n[0] + 1; + n[8] = n[7] + 1; + } + + // noise randomness uniformly distributed between 0.5 to 1.5, + // 0.5 is an empirical value. + uint32_t random_noise_scale = fixed_noise_scale + * (static_cast<double>(rand()) / RAND_MAX + 0.5); + + *n[0] = *n[0] + ((convolution_matrix[0] * random_noise_scale) >> kShiftBits); + // The value in convolution_matrix is identical (56) for indexes 1, 3, 6, 8. + uint32_t normal_scaled_noise = (convolution_matrix[1] * random_noise_scale) >> kShiftBits; + *n[1] += normal_scaled_noise; + *n[3] += normal_scaled_noise; + *n[6] += normal_scaled_noise; + *n[8] += normal_scaled_noise; + // Likewise, the computation could be saved for indexes 2, 4, 5, 7; + normal_scaled_noise = (convolution_matrix[2] * random_noise_scale) >> kShiftBits; + *n[2] += normal_scaled_noise; + *n[4] += normal_scaled_noise; + *n[5] += normal_scaled_noise; + *n[7] += normal_scaled_noise; + } + } + } +} + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeGrain( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat noise_scale) { + pGrainType f = (pGrainType)JNIFunc[JNI_Grain].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, noise_scale); +} + +extern "C" void Grain( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat noise_scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in grain failed, error=%d", ret); + return; + } + + GenerateBlurredNoise(dst_pixels, &dst_info, noise_scale); + + for (uint32_t scan_line = 0; scan_line < src_info.height; scan_line++) { + uint32_t* src = reinterpret_cast<uint32_t*>( + reinterpret_cast<char*>(src_pixels) + src_info.stride * scan_line); + uint32_t* dst = reinterpret_cast<uint32_t*>( + reinterpret_cast<char*>(dst_pixels) + dst_info.stride * scan_line); + + uint32_t* src_line_end = src + src_info.width; + while (src < src_line_end) { + pixel32_t* sp = reinterpret_cast<pixel32_t*>(src); + pixel32_t* dp = reinterpret_cast<pixel32_t*>(dst); + + // energy_mask is used to constrain the noise according to the energy + // level. Film grain appear more in dark part. + // The energy level (from 0 to 765) is square-rooted and should in the + // range from 0 to 27.659 (sqrt(765)), so 28 is used for normalization. + uint32_t energy_level = sp->rgba8[0] + sp->rgba8[1] + sp->rgba8[2]; + uint32_t energy_mask = 28 - static_cast<uint32_t>(sqrtf(energy_level)); + + // The intensity of each channel of RGB is affected by the random + // noise previously produced and stored in dp->pixel. + // dp->pixel should be in the range of [1.3 * noise_scale * kShiftValue, + // 0]. Therefore 'scale' should be in the range of + // [kShiftValue, kShiftValue - 1.3 * noise_scale * kShiftValue] + uint32_t scale = (kShiftValue - dp->rgba32 * energy_mask / 28); + uint32_t red = (sp->rgba8[0] * scale) >> kShiftBits; + uint32_t green = (sp->rgba8[1] * scale) >> kShiftBits; + uint32_t blue = (sp->rgba8[2] * scale) >> kShiftBits; + dp->rgba32 = (sp->rgba8[3] << 24) | (blue << 16) | (green << 8) | red; + + dst++; + src++; + } + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/grayscale.cpp b/samples/PhotoEditor/jni/grayscale.cpp new file mode 100644 index 0000000..8b528f8 --- /dev/null +++ b/samples/PhotoEditor/jni/grayscale.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeGrayscale( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + pGrayscaleType f = (pGrayscaleType)JNIFunc[JNI_Grayscale].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, scale); +} + +extern "C" void Grayscale( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in GrayScale failed, error=%d", ret); + return; + } + + const int kShiftBits = 20; + const int32_t kRedRatio = static_cast<int32_t>((1 << kShiftBits) * 0.21f); + const int32_t kGreenRatio = static_cast<int32_t>((1 << kShiftBits) * 0.71f); + const int32_t kBlueRatio = static_cast<int32_t>((1 << kShiftBits) * 0.07f); + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + while (src < src_line_end) { + int32_t src_red = src->rgba8[0]; + int32_t src_green = src->rgba8[1]; + int32_t src_blue = src->rgba8[2]; + int32_t src_alpha = src->rgba8[3]; + + int32_t dst_color = (kRedRatio * src_red + kGreenRatio * src_green + + kBlueRatio * src_blue) >> kShiftBits; + if (dst_color > 255) { + dst_color = 255; + } + *dst = (src_alpha << 24) | (dst_color << 16) | (dst_color << 8) | dst_color; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/heq.cpp b/samples/PhotoEditor/jni/heq.cpp new file mode 100644 index 0000000..eb4d28d --- /dev/null +++ b/samples/PhotoEditor/jni/heq.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> +#include <cstdlib> +#include <cstring> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::clamp; +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + + // Array of approximated CDF of normal distribution. + // 1024 Entries in total. The array is approximated by sigmoid function and + // the exact command in "octave" is: + // x = [2/1029:1/1029:1025/1029]; + // y = (-1/11.5*log(1./x-0.9999)+0.5)*766*0.9+766*0.05; + const int kCDFEntries = 1024; + const uint32_t normal_cdf[] = { + 9, 33, 50, 64, 75, 84, 92, 99, 106, 112, 117, 122, 126, 130, 134, 138, 142, + 145, 148, 150, 154, 157, 159, 162, 164, 166, 169, 170, 173, 175, 177, 179, + 180, 182, 184, 186, 188, 189, 190, 192, 194, 195, 197, 198, 199, 200, 202, + 203, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, + 234, 235, 236, 236, 237, 238, 239, 239, 240, 240, 242, 242, 243, 244, 245, + 245, 246, 247, 247, 248, 249, 249, 250, 250, 251, 252, 253, 253, 254, 255, + 255, 256, 256, 257, 258, 258, 259, 259, 259, 260, 261, 262, 262, 263, 263, + 264, 264, 265, 265, 266, 267, 267, 268, 268, 269, 269, 269, 270, 270, 271, + 272, 272, 273, 273, 274, 274, 275, 275, 276, 276, 277, 277, 277, 278, 278, + 279, 279, 279, 280, 280, 281, 282, 282, 282, 283, 283, 284, 284, 285, 285, + 285, 286, 286, 287, 287, 288, 288, 288, 289, 289, 289, 290, 290, 290, 291, + 292, 292, 292, 293, 293, 294, 294, 294, 295, 295, 296, 296, 296, 297, 297, + 297, 298, 298, 298, 299, 299, 299, 299, 300, 300, 301, 301, 302, 302, 302, + 303, 303, 304, 304, 304, 305, 305, 305, 306, 306, 306, 307, 307, 307, 308, + 308, 308, 309, 309, 309, 309, 310, 310, 310, 310, 311, 312, 312, 312, 313, + 313, 313, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316, 317, 317, 317, + 318, 318, 318, 319, 319, 319, 319, 319, 320, 320, 320, 321, 321, 322, 322, + 322, 323, 323, 323, 323, 324, 324, 324, 325, 325, 325, 325, 326, 326, 326, + 327, 327, 327, 327, 328, 328, 328, 329, 329, 329, 329, 329, 330, 330, 330, + 330, 331, 331, 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, 334, 335, + 335, 335, 336, 336, 336, 336, 337, 337, 337, 337, 338, 338, 338, 339, 339, + 339, 339, 339, 339, 340, 340, 340, 340, 341, 341, 342, 342, 342, 342, 343, + 343, 343, 344, 344, 344, 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, + 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, 349, 349, 349, 350, 350, + 350, 350, 351, 351, 352, 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, + 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, 357, 357, 357, 358, 358, + 358, 358, 359, 359, 359, 359, 359, 359, 359, 360, 360, 360, 360, 361, 361, + 362, 362, 362, 362, 363, 363, 363, 363, 364, 364, 364, 364, 365, 365, 365, + 365, 366, 366, 366, 366, 366, 367, 367, 367, 367, 368, 368, 368, 368, 369, + 369, 369, 369, 369, 369, 370, 370, 370, 370, 370, 371, 371, 372, 372, 372, + 372, 373, 373, 373, 373, 374, 374, 374, 374, 374, 375, 375, 375, 375, 376, + 376, 376, 376, 377, 377, 377, 377, 378, 378, 378, 378, 378, 379, 379, 379, + 379, 379, 379, 380, 380, 380, 380, 381, 381, 381, 382, 382, 382, 382, 383, + 383, 383, 383, 384, 384, 384, 384, 385, 385, 385, 385, 385, 386, 386, 386, + 386, 387, 387, 387, 387, 388, 388, 388, 388, 388, 389, 389, 389, 389, 389, + 389, 390, 390, 390, 390, 391, 391, 392, 392, 392, 392, 392, 393, 393, 393, + 393, 394, 394, 394, 394, 395, 395, 395, 395, 396, 396, 396, 396, 396, 397, + 397, 397, 397, 398, 398, 398, 398, 399, 399, 399, 399, 399, 399, 400, 400, + 400, 400, 400, 401, 401, 402, 402, 402, 402, 403, 403, 403, 403, 404, 404, + 404, 404, 405, 405, 405, 405, 406, 406, 406, 406, 406, 407, 407, 407, 407, + 408, 408, 408, 408, 409, 409, 409, 409, 409, 409, 410, 410, 410, 410, 411, + 411, 412, 412, 412, 412, 413, 413, 413, 413, 414, 414, 414, 414, 415, 415, + 415, 415, 416, 416, 416, 416, 417, 417, 417, 417, 418, 418, 418, 418, 419, + 419, 419, 419, 419, 419, 420, 420, 420, 420, 421, 421, 422, 422, 422, 422, + 423, 423, 423, 423, 424, 424, 424, 425, 425, 425, 425, 426, 426, 426, 426, + 427, 427, 427, 427, 428, 428, 428, 429, 429, 429, 429, 429, 429, 430, 430, + 430, 430, 431, 431, 432, 432, 432, 433, 433, 433, 433, 434, 434, 434, 435, + 435, 435, 435, 436, 436, 436, 436, 437, 437, 437, 438, 438, 438, 438, 439, + 439, 439, 439, 439, 440, 440, 440, 441, 441, 442, 442, 442, 443, 443, 443, + 443, 444, 444, 444, 445, 445, 445, 446, 446, 446, 446, 447, 447, 447, 448, + 448, 448, 449, 449, 449, 449, 449, 450, 450, 450, 451, 451, 452, 452, 452, + 453, 453, 453, 454, 454, 454, 455, 455, 455, 456, 456, 456, 457, 457, 457, + 458, 458, 458, 459, 459, 459, 459, 460, 460, 460, 461, 461, 462, 462, 462, + 463, 463, 463, 464, 464, 465, 465, 465, 466, 466, 466, 467, 467, 467, 468, + 468, 469, 469, 469, 469, 470, 470, 470, 471, 472, 472, 472, 473, 473, 474, + 474, 474, 475, 475, 476, 476, 476, 477, 477, 478, 478, 478, 479, 479, 479, + 480, 480, 480, 481, 482, 482, 483, 483, 484, 484, 484, 485, 485, 486, 486, + 487, 487, 488, 488, 488, 489, 489, 489, 490, 490, 491, 492, 492, 493, 493, + 494, 494, 495, 495, 496, 496, 497, 497, 498, 498, 499, 499, 499, 500, 501, + 502, 502, 503, 503, 504, 504, 505, 505, 506, 507, 507, 508, 508, 509, 509, + 510, 510, 511, 512, 513, 513, 514, 515, 515, 516, 517, 517, 518, 519, 519, + 519, 520, 521, 522, 523, 524, 524, 525, 526, 526, 527, 528, 529, 529, 530, + 531, 532, 533, 534, 535, 535, 536, 537, 538, 539, 539, 540, 542, 543, 544, + 545, 546, 547, 548, 549, 549, 550, 552, 553, 554, 555, 556, 558, 559, 559, + 561, 562, 564, 565, 566, 568, 569, 570, 572, 574, 575, 577, 578, 579, 582, + 583, 585, 587, 589, 590, 593, 595, 597, 599, 602, 604, 607, 609, 612, 615, + 618, 620, 624, 628, 631, 635, 639, 644, 649, 654, 659, 666, 673, 680, 690, + 700, 714}; + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeHEQ( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + pHEQType f = (pHEQType)JNIFunc[JNI_HEQ].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, scale); +} + +extern "C" void HEQ( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in HEQ failed, error=%d", ret); + return; + } + + const int kEnergyLevels = 766; // 255 * 3 + 1 + + // The energy has the range of [0, kEnergyLevels] + int accumulated_histogram[kEnergyLevels]; + memset(accumulated_histogram, 0, sizeof(accumulated_histogram)); + + // Store all the energy in the dst_pixels + pixel32_t* dst = reinterpret_cast<pixel32_t*>(dst_pixels); + pixel32_t const* src = reinterpret_cast<pixel32_t const*>(src_pixels); + pixel32_t const* src_end = reinterpret_cast<pixel32_t const*>( + reinterpret_cast<char const*>(src) + src_info.stride * src_info.height); + while (src < src_end) { + dst->rgba32 = src->rgba8[0] + src->rgba8[1] + src->rgba8[2]; + ++src; + ++dst; + } + + // Build up the accumulated histogram table by ignoring borders (1/20 = 5% width). + float border_thickness_ratio = 0.05; + int y_border_thickness = dst_info.height * border_thickness_ratio; + pixel32_t* dst_line = reinterpret_cast<pixel32_t*>( + reinterpret_cast<char*>(dst_pixels) + dst_info.stride * y_border_thickness); + pixel32_t* dst_line_end = reinterpret_cast<pixel32_t*>( + reinterpret_cast<char*>(dst_pixels) + dst_info.stride * + (dst_info.height - y_border_thickness)); + int x_border_thickness = dst_info.width * border_thickness_ratio; + int x_border_end = dst_info.width - x_border_thickness; + while (dst_line < dst_line_end) { + pixel32_t* dp = dst_line + x_border_thickness; + pixel32_t* dp_end = dst_line + x_border_end; + while (dp < dp_end) { + ++accumulated_histogram[dp->rgba32]; + ++dp; + } + dst_line = reinterpret_cast<pixel32_t*>( + reinterpret_cast<char*>(dst_line) + dst_info.stride); + } + + for (int i = 1; i < kEnergyLevels; i++) { + accumulated_histogram[i] += accumulated_histogram[i - 1]; + } + + uint32_t const* src_line = + reinterpret_cast<uint32_t const*>(src_pixels); + dst_line = reinterpret_cast<pixel32_t*>(dst_pixels); + dst_line_end = reinterpret_cast<pixel32_t*>(reinterpret_cast<char*>(dst_line) + + dst_info.height * dst_info.stride); + // The whole process is done by apply the HEQ result with a mask. + // The mask is a curve segmented by the energy_middle which could be tuned + // based on each bitmap. For the lower part, the mask tries to make the change + // significant for greater energy. For the smaller part, the mask does the + // contrary. The two curve should be continuous on the energy_middle so the + // final result is more natural. In this implementation, what I defined is two + // curve based on the energy 'e', for the smaller part, e^2 is used. For the + // greater part, e^1.5 is used. That is, for pixel with energy 'e', the mask + // is obtained by: + // if e > energy_middle + // (e - energy_middle)^1.5 / (765 - energy_middle)^1.5 + // else + // (e - energy_middle)^2 / (energy_middle)^2 + const int kShiftBits = 10; + const int kShiftValue = (1 << kShiftBits); + const int scale_shifted = scale * kShiftValue; + const int normalization_scale_shifted = (1.0 - scale) * kShiftValue; + const int energy_middle = 382; // 765 / 2 = 382.5 + const int normalization_low = 7481; // (765 - 382.5)^1.5 + const int normalization_high = 146307; // 382.5^2 + int total_pixels = accumulated_histogram[kEnergyLevels - 1]; + while (dst_line < dst_line_end) { + pixel32_t const* sp = reinterpret_cast<pixel32_t const*>(src_line); + pixel32_t* dp = dst_line; + pixel32_t* dp_end = dp + dst_info.width; + while (dp < dp_end) { + if (!dp->rgba32) { // the energy is 0, no changes will be made. + dp->rgba32 = sp->rgba32; + } else { + uint32_t energy = dp->rgba32; + int mask_normalization; + int mask_value = energy - energy_middle; + + if (mask_value > 0) { + mask_value = mask_value * sqrt(mask_value); + mask_normalization = normalization_low; + } else { + mask_value *= mask_value; + mask_normalization = normalization_high; + } + mask_value = ((mask_value * scale_shifted) + + (mask_normalization * (normalization_scale_shifted))) >> kShiftBits; + // The final picture is masked by the original energy. + // Assumption: Lower energy can result in low-confidence information and + // higher energy indicates good confidence. + // Therefore, pixels with low and high confidence should not be changed + // greatly. + uint32_t dst_energy = normal_cdf[ + kCDFEntries * accumulated_histogram[energy] / total_pixels]; + dst_energy = (energy * mask_value + dst_energy * (mask_normalization - mask_value)) / + mask_normalization; + + // Ensure there is no RGB value will be greater than 255. + uint32_t max_energy = energy * 255 / MAX3(sp->rgba8[0], sp->rgba8[1], sp->rgba8[2]); + if (dst_energy > max_energy) { + dst_energy = max_energy; + } + + dst_energy = (dst_energy << kShiftBits) / energy; + uint32_t dst_red = (sp->rgba8[0] * dst_energy) >> kShiftBits; + uint32_t dst_green = (sp->rgba8[1] * dst_energy) >> kShiftBits; + uint32_t dst_blue = (sp->rgba8[2] * dst_energy) >> kShiftBits; + dp->rgba32 = (sp->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + } + dp++; + sp++; + } + src_line = reinterpret_cast<uint32_t const*>( + reinterpret_cast<char const*>(src_line) + src_info.stride); + dst_line = reinterpret_cast<pixel32_t*>( + reinterpret_cast<char*>(dst_line) + dst_info.stride); + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/negative.cpp b/samples/PhotoEditor/jni/negative.cpp new file mode 100644 index 0000000..ee90609 --- /dev/null +++ b/samples/PhotoEditor/jni/negative.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeNegative( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pNegativeType f = (pNegativeType)JNIFunc[JNI_Negative].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void Negative( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Negative failed, error=%d", ret); + return; + } + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + uint32_t dst_red = 0xff - src->rgba8[0]; + uint32_t dst_green = 0xff - src->rgba8[1]; + uint32_t dst_blue = 0xff - src->rgba8[2]; + uint32_t src_alpha = src->rgba8[3]; + + *dst = (src_alpha << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/quantize.cpp b/samples/PhotoEditor/jni/quantize.cpp new file mode 100644 index 0000000..cd43f66 --- /dev/null +++ b/samples/PhotoEditor/jni/quantize.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> +#include <cstdlib> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeQuantize( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pQuantizeType f = (pQuantizeType)JNIFunc[JNI_Quantize].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void Quantize( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in quantize failed, error=%d", ret); + return; + } + + uint8_t quantize_map[256]; + + for (uint32_t i = 0; i < 256; i++) { + quantize_map[i] = i / 128 * 128 + 64; + } + + for (uint32_t scan_line = 0; scan_line < src_info.height; scan_line++) { + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* dst = reinterpret_cast<pixel32_t*>(dst_pixels); + + pixel32_t* src_line_end = src + src_info.width; + while (src < src_line_end) { + dst->rgba8[0] = quantize_map[src->rgba8[0]]; + dst->rgba8[1] = quantize_map[src->rgba8[1]]; + dst->rgba8[2] = quantize_map[src->rgba8[2]]; + dst->rgba8[3] = src->rgba8[3]; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/redeye.cpp b/samples/PhotoEditor/jni/redeye.cpp new file mode 100644 index 0000000..af828d8 --- /dev/null +++ b/samples/PhotoEditor/jni/redeye.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> +#include <cstdlib> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeRedEye( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, + jobjectArray redeye_positions, jfloat radius, jfloat intensity) { + pRedEyeType f = (pRedEyeType)JNIFunc[JNI_RedEye].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, redeye_positions, radius, intensity); +} + +extern "C" void RedEye( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, + jobjectArray redeye_positions, jfloat radius, jfloat intensity) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in RedEye failed, error=%d", ret); + return; + } + + memcpy(dst_pixels, src_pixels, src_info.stride * src_info.height); + + // get the class reference. + jclass cls = env->FindClass("android/graphics/PointF"); + jfieldID xid = env->GetFieldID(cls, "x", "F"); + jfieldID yid = env->GetFieldID(cls, "y", "F"); + int eye_number = env->GetArrayLength(redeye_positions); + for (int eye = 0; eye < eye_number; eye++) { + jobject point_f = env->GetObjectArrayElement(redeye_positions, eye); + float focus_x = env->GetFloatField(point_f, xid); + float focus_y = env->GetFloatField(point_f, yid); + if (focus_x < 0.0 || focus_x > 1.0 || focus_y < 0.0 || focus_y > 1.0) { + // did not tap on the picture + continue; + } + + float x = focus_x * src_info.width; + float y = focus_y * src_info.height; + uint32_t bound_y = y + radius; + if (bound_y > dst_info.height) { + bound_y = dst_info.height; + } + uint32_t start_x = (x > radius) ? x - radius: 0; + uint32_t bound_x = x + radius; + if (bound_x > dst_info.width) { + bound_x = dst_info.width; + } + uint32_t dst_y = (y > radius) ? y - radius : 0; + for (; dst_y < bound_y; dst_y++) { + uint32_t *dst = reinterpret_cast<uint32_t*>( + reinterpret_cast<char*>(dst_pixels) + dst_info.stride * dst_y) + start_x; + pixel32_t *src = reinterpret_cast<pixel32_t*>( + reinterpret_cast<char*>(src_pixels) + src_info.stride * dst_y) + start_x; + for (uint32_t dst_x = start_x; dst_x < bound_x; dst_x++) { + if (hypotf(dst_x - x, dst_y - y) <= radius) { + int32_t red = src->rgba8[0]; + int32_t green = src->rgba8[1]; + int32_t blue = src->rgba8[2]; + int32_t alpha = src->rgba8[3]; + + float redIntensity = static_cast<float>(red) / (green + blue); + if (redIntensity > intensity) { + red = (green + blue) / 2.0f; + *dst = alpha << 24 | (blue << 16) | (green << 8) | red; + } + } + dst++; + src++; + } // dst_x + } // dst_y + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/saturate.cpp b/samples/PhotoEditor/jni/saturate.cpp new file mode 100644 index 0000000..29693e7 --- /dev/null +++ b/samples/PhotoEditor/jni/saturate.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +const int k256Multiply255 = 65280; + +void BenSaturate(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, + void *src_pixels, void *dst_pixels, int scale) { + for (uint32_t scan_line = 0; scan_line < dst_info->height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_end = src + src_info->width; + + while (src < src_end) { + int kv = (src->rgba8[0] + src->rgba8[0] + src->rgba8[1] * 5 + src->rgba8[2] + 4) >> 3; + + int dst_red = kv + (((src->rgba8[0] - kv) * scale) >> 8); + int dst_green = kv + (((src->rgba8[1] - kv) * scale) >> 8); + int dst_blue = kv + (((src->rgba8[2] - kv) * scale) >> 8); + + *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride; + } +} + +void HerfSaturate(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, + void *src_pixels, void *dst_pixels, float scale) { + const float kMapScale = 8.0; + const int kMapSize = 2048; + int rmap[kMapSize]; + int gmap[kMapSize]; + int bmap[kMapSize]; + + const float kR = 0.3; + const float kG = 0.7; + const float kB = 0.9; + const float amtR = (kR * scale) + 1; + const float amtG = (kG * scale) + 1; + const float amtB = (kB * scale) + 1; + + for (int i = 0; i < kMapSize; i++) { + float inv = kMapScale * static_cast<float>(i) / kMapSize; + rmap[i] = static_cast<int>(pow(inv, amtR) * 256); + gmap[i] = static_cast<int>(pow(inv, amtG) * 256); + bmap[i] = static_cast<int>(pow(inv, amtB) * 256); + } + + int kMapFactor256 = static_cast<int>(kMapSize / kMapScale) * 256; + for (uint32_t scan_line = 0; scan_line < dst_info->height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_end = src + src_info->width; + + while (src < src_end) { + int de = (src->rgba8[0] + src->rgba8[0] + src->rgba8[1] * 5 + src->rgba8[2]) >> 3; + if (!de) { + *dst = src->rgba8[3] << 24; + } else { + int invde = (kMapFactor256 - 1) / de; + int r = invde * src->rgba8[0] >> 8; + int g = invde * src->rgba8[1] >> 8; + int b = invde * src->rgba8[2] >> 8; + + int dst_red = de * rmap[r] >> 8; + int dst_green = de * gmap[g] >> 8; + int dst_blue = de * bmap[b] >> 8; + + int rgb_max = MAX3(dst_red, dst_green, dst_blue); + if (rgb_max > 255) { + int invmax = k256Multiply255 / rgb_max; + dst_red = dst_red * invmax >> 8; + dst_green = dst_green * invmax >> 8; + dst_blue = dst_blue * invmax >> 8; + } + + *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + } + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride; + } +} + +/* + * @param scale ranges from -1 to 1. + */ +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeSaturation( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + pSaturationType f = (pSaturationType)JNIFunc[JNI_Saturation].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, scale); +} + +extern "C" void Saturation( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Saturation failed, error=%d", ret); + return; + } + + if (scale >= 0) { + HerfSaturate(&src_info, &dst_info, src_pixels, dst_pixels, scale * 3); + } else { + BenSaturate(&src_info, &dst_info, src_pixels, dst_pixels, + static_cast<int>((1 + scale) * 256)); + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/sepia.cpp b/samples/PhotoEditor/jni/sepia.cpp new file mode 100644 index 0000000..ea54d4c --- /dev/null +++ b/samples/PhotoEditor/jni/sepia.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeSepia( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pSepiaType f = (pSepiaType)JNIFunc[JNI_Sepia].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void Sepia( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Sepia failed, error=%d", ret); + return; + } + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + while (src < src_line_end) { + int dst_red = (src->rgba8[0] * 805 + src->rgba8[1] * 1575 + src->rgba8[2] * 387) >> 11; + int dst_green = (src->rgba8[0] * 715 + src->rgba8[1] * 1405 + src->rgba8[2] * 344) >> 11; + int dst_blue = (src->rgba8[0] * 557 + src->rgba8[1] * 1094 + src->rgba8[2] * 268) >> 11; + + if (dst_red > 255) { + dst_red = 255; + } + if (dst_green > 255) { + dst_green = 255; + } + if (dst_blue > 255) { + dst_blue = 255; + } + + *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/sharpen.cpp b/samples/PhotoEditor/jni/sharpen.cpp new file mode 100644 index 0000000..3c0514e --- /dev/null +++ b/samples/PhotoEditor/jni/sharpen.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "convolution.h" +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::convolution::SpecialConvolution; +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeSharpen( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + pSharpenType f = (pSharpenType)JNIFunc[JNI_Sharpen].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, scale); +} + +extern "C" void Sharpen( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Sharpen failed, error=%d", ret); + return; + } + + SpecialConvolution(&src_info, &dst_info, src_pixels, dst_pixels, -scale); + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/tint.cpp b/samples/PhotoEditor/jni/tint.cpp new file mode 100644 index 0000000..23c7fe4 --- /dev/null +++ b/samples/PhotoEditor/jni/tint.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeTint( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint tint) { + pTintType f = (pTintType)JNIFunc[JNI_Tint].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, tint); +} + +extern "C" void Tint( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jint tint) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Tint failed, error=%d", ret); + return; + } + + const int kShiftBits = 10; + const int kRedRatio = static_cast<int>(0.8f * (1 << kShiftBits) * 0.21f); + const int kGreenRatio = static_cast<int>(0.8f * (1 << kShiftBits) * 0.71f); + const int kBlueRatio = static_cast<int>(0.8f * (1 << kShiftBits) * 0.07f); + const int kTintRatio = static_cast<int>(0.2f * (1 << kShiftBits)); + + uint32_t tint_red = kTintRatio * ((tint >> 16) & 0xff); + uint32_t tint_green = kTintRatio * ((tint >> 8) & 0xff); + uint32_t tint_blue = kTintRatio * (tint & 0xff); + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + while (src < src_line_end) { + int32_t avg = kRedRatio * src->rgba8[0] + kGreenRatio * src->rgba8[1] + + kBlueRatio * src->rgba8[2]; + + int32_t dst_red = (avg + tint_red) >> kShiftBits; + int32_t dst_green = (avg + tint_green) >> kShiftBits; + int32_t dst_blue = (avg + tint_blue) >> kShiftBits; + + if (dst_red > 255) { + dst_red = 255; + } + if (dst_green > 255) { + dst_green = 255; + } + if (dst_blue > 255) { + dst_blue = 255; + } + + *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; + dst++; + src++; + } + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/utils.cpp b/samples/PhotoEditor/jni/utils.cpp new file mode 100644 index 0000000..d16eceb --- /dev/null +++ b/samples/PhotoEditor/jni/utils.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 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 "utils.h" + +#include <android/bitmap.h> + +namespace android { +namespace apps { +namespace photoeditor { +namespace utils { + +int ExtractInfoFromBitmap(JNIEnv *env, + AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, + jobject src_bitmap, jobject dst_bitmap) { + int ret; + /* + * The info->format of both bitmap should be ANDROID_BITMAP_FORMAT_RGBA_8888. + * Both bitmaps shall also be in the same dimension. + */ + if ((ret = AndroidBitmap_getInfo(env, src_bitmap, src_info)) < 0) { + LOGE("AndroidBitmap_getInfo(src_bitmap) failed, error=%d", ret); + return ret; + } + if ((ret = AndroidBitmap_getInfo(env, dst_bitmap, dst_info)) < 0) { + LOGE("AndroidBitmap_getInfo(dst_bitmap) failed, error=%d", ret); + return ret; + } + return 0; +} + +int LockBitmaps(JNIEnv* env, jobject src_bitmap, jobject dst_bitmap, + AndroidBitmapInfo* src_info, AndroidBitmapInfo* dst_info, + void** src_pixels, void** dst_pixels) { + int ret; + if ((ret = ExtractInfoFromBitmap(env, src_info, dst_info, src_bitmap, dst_bitmap)) < 0) { + return ret; + } + if ((ret = AndroidBitmap_lockPixels(env, src_bitmap, src_pixels)) < 0) { + LOGE("AndroidBitmap_lockPixels(src_bitmap) failed, error=%d", ret); + return ret; + } + if ((ret = AndroidBitmap_lockPixels(env, dst_bitmap, dst_pixels)) < 0) { + LOGE("AndroidBitmap_lockPixels(dst_bitmap) failed, error=%d", ret); + AndroidBitmap_unlockPixels(env, src_bitmap); + return ret; + } + return 0; +} + +void UnlockBitmaps(JNIEnv* env, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmap_unlockPixels(env, src_bitmap); + AndroidBitmap_unlockPixels(env, dst_bitmap); +} + +} // namespace utils +} // namespace photoeditor +} // namespace apps +} // namespace android + diff --git a/samples/PhotoEditor/jni/utils.h b/samples/PhotoEditor/jni/utils.h new file mode 100644 index 0000000..af4bb54 --- /dev/null +++ b/samples/PhotoEditor/jni/utils.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 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 PHOTOEDITOR_JNI_UTILS_H_ +#define PHOTOEDITOR_JNI_UTILS_H_ + +#include <android/bitmap.h> +#include <android/log.h> +#include <jni.h> + +#define LOG_TAG "libjni_photoeditor" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) + +#define MIN3(x, y, z) ((y) <= (z) ? \ + ((x) <= (y) ? (x) : (y)) \ + : \ + ((x) <= (z) ? (x) : (z))) + +#define MAX3(x, y, z) ((y) >= (z) ? \ + ((x) >= (y) ? (x) : (y)) \ + : \ + ((x) >= (z) ? (x) : (z))) + +namespace android { +namespace apps { +namespace photoeditor { +namespace utils { + +inline int clamp(int x, int min, int max) { + return (x < min ? min : ((x > max) ? max : x)); +} + +union pixel32_t { + uint32_t rgba32; + uint8_t rgba8[4]; // 0: red 1:green 2:blue 3:alpha +}; + +typedef union pixel32_t pixel32_t; + +int ExtractInfoFromBitmap(JNIEnv *env, + AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, + jobject src_bitmap, jobject dst_bitmap); + +int LockBitmaps(JNIEnv* env, jobject src_bitmap, jobject dst_bitmap, + AndroidBitmapInfo* src_info, AndroidBitmapInfo* dst_info, + void** src_pixels, void** dst_pixels); + +void UnlockBitmaps(JNIEnv* env, jobject src_bitmap, jobject dst_bitmap); + +} // namespace utils +} // namespace photoeditor +} // namespace apps +} // namespace android + + +#endif // PHOTOEDITOR_JNI_UTILS_H_ diff --git a/samples/PhotoEditor/jni/vignetting.cpp b/samples/PhotoEditor/jni/vignetting.cpp new file mode 100644 index 0000000..3451e9d --- /dev/null +++ b/samples/PhotoEditor/jni/vignetting.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +/** + * @param range the position of the significant falloff of light (50% luminosity). + */ +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeVignetting( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat range) { + pVignettingType f = (pVignettingType)JNIFunc[JNI_Vignetting].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, range); +} + +extern "C" void Vignetting( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat range) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + const float slope = 20.0f; // how fast the light changes, the bigger the faster. + range *= slope; + const int kShiftBits = 10; + const uint32_t shade = 0.85 * (1 << kShiftBits); // the intensity of the shade + const uint32_t shade_offset = (1 << kShiftBits) - shade; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in Vignetting failed, error=%d", ret); + return; + } + + const uint32_t center_x = src_info.width / 2; + const uint32_t center_y = src_info.height / 2; + const uint32_t hypot = sqrt(center_x * center_x + center_y * center_y) / slope; + + for (uint32_t dst_y = 0; dst_y < dst_info.height; dst_y++) { + uint32_t *dst = reinterpret_cast<uint32_t*>( + reinterpret_cast<char*>(dst_pixels) + dst_info.stride * dst_y); + pixel32_t *src = reinterpret_cast<pixel32_t*>( + reinterpret_cast<char*>(src_pixels) + src_info.stride * dst_y); + int dy = dst_y - center_y; + for (uint32_t dst_x = 0; dst_x < dst_info.width; dst_x++) { + int dx = dst_x - center_x; + int dist_square = dx * dx + dy * dy; + uint32_t luminousity = shade / (1 + exp(sqrt(dist_square) / hypot - range)) + + shade_offset; + uint32_t red = (luminousity * src->rgba8[0]) >> kShiftBits; + uint32_t green = (luminousity * src->rgba8[1]) >> kShiftBits; + uint32_t blue = (luminousity * src->rgba8[2]) >> kShiftBits; + uint32_t alpha = src->rgba8[3]; + *dst = (alpha << 24) | (blue << 16) | (green << 8) | red; + dst++; + src++; + } // dst_x + } // dst_y + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/warmify.cpp b/samples/PhotoEditor/jni/warmify.cpp new file mode 100644 index 0000000..5bf702a --- /dev/null +++ b/samples/PhotoEditor/jni/warmify.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +const int map[256] = { + 0xff000000,0xff010101,0xff030201,0xff040302,0xff050303,0xff060403,0xff080504,0xff090605, + 0xff0a0705,0xff0c0806,0xff0d0907,0xff0e0907,0xff0f0a08,0xff110b09,0xff120c09,0xff130d0a, + 0xff140e0b,0xff160f0b,0xff17100c,0xff18100d,0xff1a110d,0xff1b120e,0xff1c130f,0xff1d140f, + 0xff1f1510,0xff201611,0xff211711,0xff221812,0xff241913,0xff251a13,0xff261b14,0xff271c15, + 0xff291d15,0xff2a1e16,0xff2b1f17,0xff2c2017,0xff2e2118,0xff2f2119,0xff30221a,0xff31231a, + 0xff32241b,0xff34251c,0xff35261c,0xff36271d,0xff37281e,0xff38291e,0xff3a2a1f,0xff3b2b20, + 0xff3c2c20,0xff3d2d21,0xff3e2e22,0xff402f23,0xff413023,0xff423124,0xff433225,0xff443325, + 0xff463426,0xff473527,0xff483628,0xff493728,0xff4a3829,0xff4b392a,0xff4c3a2b,0xff4e3b2b, + 0xff4f3c2c,0xff503d2d,0xff513e2d,0xff523f2e,0xff53402f,0xff544130,0xff554130,0xff564231, + 0xff574332,0xff594433,0xff5a4533,0xff5b4634,0xff5c4735,0xff5d4836,0xff5e4937,0xff5f4a37, + 0xff604b38,0xff614c39,0xff624c3a,0xff634d3a,0xff644e3b,0xff654f3c,0xff66503d,0xff67513e, + 0xff68523e,0xff69533f,0xff6a5340,0xff6b5441,0xff6c5542,0xff6d5642,0xff6e5743,0xff6f5844, + 0xff705845,0xff715946,0xff715a47,0xff725b47,0xff735c48,0xff745c49,0xff755d4a,0xff765e4b, + 0xff775f4c,0xff785f4c,0xff79604d,0xff7a614e,0xff7a624f,0xff7b6350,0xff7c6351,0xff7d6452, + 0xff7e6552,0xff7f6653,0xff806654,0xff806755,0xff816856,0xff826957,0xff836958,0xff846a59, + 0xff856b5a,0xff856c5a,0xff866c5b,0xff876d5c,0xff886e5d,0xff896f5e,0xff896f5f,0xff8a7060, + 0xff8b7161,0xff8c7262,0xff8d7263,0xff8d7364,0xff8e7465,0xff8f7565,0xff907566,0xff907667, + 0xff917768,0xff927869,0xff93796a,0xff94796b,0xff947a6c,0xff957b6d,0xff967c6e,0xff977c6f, + 0xff977d70,0xff987e71,0xff997f72,0xff9a8073,0xff9a8074,0xff9b8175,0xff9c8276,0xff9d8377, + 0xff9d8478,0xff9e8479,0xff9f857a,0xffa0867b,0xffa0877c,0xffa1887d,0xffa2897e,0xffa3897f, + 0xffa38a80,0xffa48b81,0xffa58c82,0xffa68d83,0xffa68e84,0xffa78f85,0xffa89086,0xffa89087, + 0xffa99188,0xffaa9289,0xffab938a,0xffab948b,0xffac958c,0xffad968e,0xffae978f,0xffae9890, + 0xffaf9991,0xffb09992,0xffb19a93,0xffb19b94,0xffb29c95,0xffb39d96,0xffb49e97,0xffb49f98, + 0xffb5a099,0xffb6a19a,0xffb7a29c,0xffb8a39d,0xffb8a49e,0xffb9a59f,0xffbaa6a0,0xffbba7a1, + 0xffbba8a2,0xffbca9a3,0xffbdaaa4,0xffbeaba5,0xffbfaba7,0xffbfaca8,0xffc0ada9,0xffc1aeaa, + 0xffc2afab,0xffc3b0ac,0xffc3b1ad,0xffc4b2ae,0xffc5b3af,0xffc6b4b1,0xffc7b5b2,0xffc7b6b3, + 0xffc8b7b4,0xffc9b8b5,0xffcab9b6,0xffcbbab7,0xffccbbb8,0xffcdbcba,0xffcdbdbb,0xffcebebc, + 0xffcfbfbd,0xffd0c0be,0xffd1c1bf,0xffd2c3c0,0xffd3c4c2,0xffd3c5c3,0xffd4c6c4,0xffd5c7c5, + 0xffd6c8c6,0xffd7c9c7,0xffd8cac8,0xffd9cbca,0xffdacccb,0xffdacdcc,0xffdbcecd,0xffdccfce, + 0xffddd0cf,0xffded1d1,0xffdfd2d2,0xffe0d3d3,0xffe1d4d4,0xffe2d5d5,0xffe3d6d6,0xffe3d7d7, + 0xffe4d8d9,0xffe5d9da,0xffe6dadb,0xffe7dbdc,0xffe8dcdd,0xffe9ddde,0xffeadfe0,0xffebe0e1, + 0xffece1e2,0xffede2e3,0xffede3e4,0xffeee4e5,0xffefe5e7,0xfff0e6e8,0xfff1e7e9,0xfff2e8ea +}; + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeWarmify( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + pWarmifyType f = (pWarmifyType)JNIFunc[JNI_Warmify].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap); +} + +extern "C" void Warmify( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in nativeWarmify failed, error=%d", ret); + return; + } + + for (uint32_t scan_line = 0; scan_line < dst_info.height; scan_line++) { + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + pixel32_t* src_line_end = src + src_info.width; + + while (src < src_line_end) { + int dst_red = (map[src->rgba8[0]] & 0xFF0000) >> 16; + int dst_green = map[src->rgba8[1]] & 0xFF00; + int dst_blue = (map[src->rgba8[2]] & 0xFF) << 16; + + *dst = (src->rgba8[3] << 24) | dst_blue | dst_green | dst_red; + + src++; + dst++; + } + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/jni/whiteblack.cpp b/samples/PhotoEditor/jni/whiteblack.cpp new file mode 100644 index 0000000..6bc6c36 --- /dev/null +++ b/samples/PhotoEditor/jni/whiteblack.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010 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 <android/bitmap.h> +#include <jni.h> + +#include <cmath> +#include <cstdlib> +#include <ctime> + +#include "utils.h" +#include "_jni.h" + +using android::apps::photoeditor::utils::clamp; +using android::apps::photoeditor::utils::LockBitmaps; +using android::apps::photoeditor::utils::pixel32_t; +using android::apps::photoeditor::utils::UnlockBitmaps; + +namespace { + +const int k256Multiply255 = 65280; + +void WhiteblackXF(float white, float black, int xform[]) { + float scale = (black != white) ? 1.0f / (white - black) : 2000.0f; + float offset = k256Multiply255 * black; + for (int i = 0; i < 256; i++) { + float vgamma = (256.0f * i - offset) * scale; + xform[i] = clamp(floor(vgamma), 0, k256Multiply255); + } + xform[256] = xform[255]; +} + +extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeWhiteBlack( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat white, jfloat black) { + pWhiteBlackType f = (pWhiteBlackType)JNIFunc[JNI_WhiteBlack].func_ptr; + return f(env, obj, src_bitmap, dst_bitmap, white, black); +} + +extern "C" void WhiteBlack( + JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat white, jfloat black) { + AndroidBitmapInfo src_info; + AndroidBitmapInfo dst_info; + void* src_pixels; + void* dst_pixels; + + int ret = LockBitmaps( + env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); + if (ret < 0) { + LOGE("LockBitmaps in WhiteBlack failed, error=%d", ret); + return; + } + + srandom(time(NULL)); + + int xform[257]; + WhiteblackXF(white, black, xform); + + for (uint32_t scan_line = 0; scan_line < src_info.height; scan_line++) { + pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); + uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); + pixel32_t* src_line_end = src + src_info.width; + while (src < src_line_end) { + int32_t red = src->rgba8[0]; + int32_t green = src->rgba8[1]; + int32_t blue = src->rgba8[2]; + int32_t alpha = src->rgba8[3]; + + int32_t xform_red = xform[red]; + int32_t xform_green = xform[green]; + int32_t xform_blue = xform[blue]; + + red = xform[red + 1] - xform_red; + green = xform[green + 1] - xform_green; + blue = xform[blue + 1] - xform_blue; + + int32_t dither = random() % 256; + int32_t diff_red = red * dither >> 8; + int32_t diff_green = green * dither >> 8; + int32_t diff_blue = blue * dither >> 8; + + red = (xform_red + diff_red - (red >> 1)) >> 8; + green = (xform_green + diff_green - (green >> 1)) >> 8; + blue = (xform_blue + diff_blue - (blue >> 1)) >> 8; + + red = clamp(red, 0, 255); + green = clamp(green, 0, 255); + blue = clamp(blue, 0, 255); + + *dst = (alpha << 24) | (blue << 16) | (green << 8) | red; + src++; + dst++; + } + src_pixels = reinterpret_cast<char*>(src_pixels) + src_info.stride; + dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info.stride; + } + + UnlockBitmaps(env, src_bitmap, dst_bitmap); +} + +} // namespace diff --git a/samples/PhotoEditor/res/anim/fade_in.xml b/samples/PhotoEditor/res/anim/fade_in.xml new file mode 100644 index 0000000..7334041 --- /dev/null +++ b/samples/PhotoEditor/res/anim/fade_in.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:fromAlpha="0.25" + android:toAlpha="1.0" + android:duration="500" + android:fillAfter="true"/> diff --git a/samples/PhotoEditor/res/anim/fade_out.xml b/samples/PhotoEditor/res/anim/fade_out.xml new file mode 100644 index 0000000..ad97c49 --- /dev/null +++ b/samples/PhotoEditor/res/anim/fade_out.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:fromAlpha="1.0" + android:toAlpha="0.25" + android:duration="500" + android:fillAfter="true"/> diff --git a/samples/PhotoEditor/res/anim/wheel_hide.xml b/samples/PhotoEditor/res/anim/wheel_hide.xml new file mode 100644 index 0000000..e79e346 --- /dev/null +++ b/samples/PhotoEditor/res/anim/wheel_hide.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<translate xmlns:android="http://schemas.android.com/apk/res/android" + android:fromXDelta="0%" + android:toXDelta="-100%" + android:duration="300"/> diff --git a/samples/PhotoEditor/res/anim/wheel_show.xml b/samples/PhotoEditor/res/anim/wheel_show.xml new file mode 100644 index 0000000..9fef1e2 --- /dev/null +++ b/samples/PhotoEditor/res/anim/wheel_show.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<translate xmlns:android="http://schemas.android.com/apk/res/android" + android:fromXDelta="-100%" + android:toXDelta="0%" + android:duration="300"/> diff --git a/samples/PhotoEditor/res/drawable/actionbar_translucent.9.png b/samples/PhotoEditor/res/drawable/actionbar_translucent.9.png Binary files differnew file mode 100644 index 0000000..f18761f --- /dev/null +++ b/samples/PhotoEditor/res/drawable/actionbar_translucent.9.png diff --git a/samples/PhotoEditor/res/drawable/arrow_back.png b/samples/PhotoEditor/res/drawable/arrow_back.png Binary files differnew file mode 100644 index 0000000..897a1c1 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/arrow_back.png diff --git a/samples/PhotoEditor/res/drawable/arrow_down.png b/samples/PhotoEditor/res/drawable/arrow_down.png Binary files differnew file mode 100644 index 0000000..ef6dd97 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/arrow_down.png diff --git a/samples/PhotoEditor/res/drawable/arrow_right.png b/samples/PhotoEditor/res/drawable/arrow_right.png Binary files differnew file mode 100644 index 0000000..87893f7 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/arrow_right.png diff --git a/samples/PhotoEditor/res/drawable/autofix_off.png b/samples/PhotoEditor/res/drawable/autofix_off.png Binary files differnew file mode 100644 index 0000000..f0e2d46 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/autofix_off.png diff --git a/samples/PhotoEditor/res/drawable/autofix_on.png b/samples/PhotoEditor/res/drawable/autofix_on.png Binary files differnew file mode 100644 index 0000000..9f1da69 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/autofix_on.png diff --git a/samples/PhotoEditor/res/drawable/colortemperature_off.png b/samples/PhotoEditor/res/drawable/colortemperature_off.png Binary files differnew file mode 100644 index 0000000..d4f1355 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/colortemperature_off.png diff --git a/samples/PhotoEditor/res/drawable/colortemperature_on.png b/samples/PhotoEditor/res/drawable/colortemperature_on.png Binary files differnew file mode 100644 index 0000000..7569b57 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/colortemperature_on.png diff --git a/samples/PhotoEditor/res/drawable/crop_height_holo.png b/samples/PhotoEditor/res/drawable/crop_height_holo.png Binary files differnew file mode 100644 index 0000000..19fdb87 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/crop_height_holo.png diff --git a/samples/PhotoEditor/res/drawable/crop_off.png b/samples/PhotoEditor/res/drawable/crop_off.png Binary files differnew file mode 100644 index 0000000..cdea423 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/crop_off.png diff --git a/samples/PhotoEditor/res/drawable/crop_on.png b/samples/PhotoEditor/res/drawable/crop_on.png Binary files differnew file mode 100644 index 0000000..4f5c298 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/crop_on.png diff --git a/samples/PhotoEditor/res/drawable/crop_width_holo.png b/samples/PhotoEditor/res/drawable/crop_width_holo.png Binary files differnew file mode 100644 index 0000000..3c82e11 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/crop_width_holo.png diff --git a/samples/PhotoEditor/res/drawable/crossprocess_off.png b/samples/PhotoEditor/res/drawable/crossprocess_off.png Binary files differnew file mode 100644 index 0000000..f9e596a --- /dev/null +++ b/samples/PhotoEditor/res/drawable/crossprocess_off.png diff --git a/samples/PhotoEditor/res/drawable/crossprocess_on.png b/samples/PhotoEditor/res/drawable/crossprocess_on.png Binary files differnew file mode 100644 index 0000000..5564db3 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/crossprocess_on.png diff --git a/samples/PhotoEditor/res/drawable/documentary_off.png b/samples/PhotoEditor/res/drawable/documentary_off.png Binary files differnew file mode 100644 index 0000000..92c40f9 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/documentary_off.png diff --git a/samples/PhotoEditor/res/drawable/documentary_on.png b/samples/PhotoEditor/res/drawable/documentary_on.png Binary files differnew file mode 100644 index 0000000..ff63406 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/documentary_on.png diff --git a/samples/PhotoEditor/res/drawable/doodle_off.png b/samples/PhotoEditor/res/drawable/doodle_off.png Binary files differnew file mode 100644 index 0000000..5b63178 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/doodle_off.png diff --git a/samples/PhotoEditor/res/drawable/doodle_on.png b/samples/PhotoEditor/res/drawable/doodle_on.png Binary files differnew file mode 100644 index 0000000..f8a7592 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/doodle_on.png diff --git a/samples/PhotoEditor/res/drawable/duotone_off.png b/samples/PhotoEditor/res/drawable/duotone_off.png Binary files differnew file mode 100644 index 0000000..994e104 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/duotone_off.png diff --git a/samples/PhotoEditor/res/drawable/duotone_on.png b/samples/PhotoEditor/res/drawable/duotone_on.png Binary files differnew file mode 100644 index 0000000..6f71b75 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/duotone_on.png diff --git a/samples/PhotoEditor/res/drawable/filllight_off.png b/samples/PhotoEditor/res/drawable/filllight_off.png Binary files differnew file mode 100644 index 0000000..999b7f7 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/filllight_off.png diff --git a/samples/PhotoEditor/res/drawable/filllight_on.png b/samples/PhotoEditor/res/drawable/filllight_on.png Binary files differnew file mode 100644 index 0000000..eff5c59 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/filllight_on.png diff --git a/samples/PhotoEditor/res/drawable/fisheye_off.png b/samples/PhotoEditor/res/drawable/fisheye_off.png Binary files differnew file mode 100644 index 0000000..5fd1b93 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/fisheye_off.png diff --git a/samples/PhotoEditor/res/drawable/fisheye_on.png b/samples/PhotoEditor/res/drawable/fisheye_on.png Binary files differnew file mode 100644 index 0000000..851141f --- /dev/null +++ b/samples/PhotoEditor/res/drawable/fisheye_on.png diff --git a/samples/PhotoEditor/res/drawable/flip_off.png b/samples/PhotoEditor/res/drawable/flip_off.png Binary files differnew file mode 100644 index 0000000..cdea423 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/flip_off.png diff --git a/samples/PhotoEditor/res/drawable/flip_on.png b/samples/PhotoEditor/res/drawable/flip_on.png Binary files differnew file mode 100644 index 0000000..4f5c298 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/flip_on.png diff --git a/samples/PhotoEditor/res/drawable/grain_off.png b/samples/PhotoEditor/res/drawable/grain_off.png Binary files differnew file mode 100644 index 0000000..f6ff7fa --- /dev/null +++ b/samples/PhotoEditor/res/drawable/grain_off.png diff --git a/samples/PhotoEditor/res/drawable/grain_on.png b/samples/PhotoEditor/res/drawable/grain_on.png Binary files differnew file mode 100644 index 0000000..7533af3 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/grain_on.png diff --git a/samples/PhotoEditor/res/drawable/grayscale_off.png b/samples/PhotoEditor/res/drawable/grayscale_off.png Binary files differnew file mode 100644 index 0000000..3c09cd3 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/grayscale_off.png diff --git a/samples/PhotoEditor/res/drawable/grayscale_on.png b/samples/PhotoEditor/res/drawable/grayscale_on.png Binary files differnew file mode 100644 index 0000000..4df7c4d --- /dev/null +++ b/samples/PhotoEditor/res/drawable/grayscale_on.png diff --git a/samples/PhotoEditor/res/drawable/group_header.9.png b/samples/PhotoEditor/res/drawable/group_header.9.png Binary files differnew file mode 100644 index 0000000..a535678 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/group_header.9.png diff --git a/samples/PhotoEditor/res/drawable/highlight_off.png b/samples/PhotoEditor/res/drawable/highlight_off.png Binary files differnew file mode 100644 index 0000000..1d59fb4 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/highlight_off.png diff --git a/samples/PhotoEditor/res/drawable/highlight_on.png b/samples/PhotoEditor/res/drawable/highlight_on.png Binary files differnew file mode 100644 index 0000000..88c580e --- /dev/null +++ b/samples/PhotoEditor/res/drawable/highlight_on.png diff --git a/samples/PhotoEditor/res/drawable/icon.png b/samples/PhotoEditor/res/drawable/icon.png Binary files differnew file mode 100644 index 0000000..34410f8 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/icon.png diff --git a/samples/PhotoEditor/res/drawable/lomoish_off.png b/samples/PhotoEditor/res/drawable/lomoish_off.png Binary files differnew file mode 100644 index 0000000..ee347e6 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/lomoish_off.png diff --git a/samples/PhotoEditor/res/drawable/lomoish_on.png b/samples/PhotoEditor/res/drawable/lomoish_on.png Binary files differnew file mode 100644 index 0000000..b6059ec --- /dev/null +++ b/samples/PhotoEditor/res/drawable/lomoish_on.png diff --git a/samples/PhotoEditor/res/drawable/negative_off.png b/samples/PhotoEditor/res/drawable/negative_off.png Binary files differnew file mode 100644 index 0000000..96da62c --- /dev/null +++ b/samples/PhotoEditor/res/drawable/negative_off.png diff --git a/samples/PhotoEditor/res/drawable/negative_on.png b/samples/PhotoEditor/res/drawable/negative_on.png Binary files differnew file mode 100644 index 0000000..cc732d9 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/negative_on.png diff --git a/samples/PhotoEditor/res/drawable/posterize_off.png b/samples/PhotoEditor/res/drawable/posterize_off.png Binary files differnew file mode 100644 index 0000000..ac5384b --- /dev/null +++ b/samples/PhotoEditor/res/drawable/posterize_off.png diff --git a/samples/PhotoEditor/res/drawable/posterize_on.png b/samples/PhotoEditor/res/drawable/posterize_on.png Binary files differnew file mode 100644 index 0000000..eed1284 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/posterize_on.png diff --git a/samples/PhotoEditor/res/drawable/quickview.png b/samples/PhotoEditor/res/drawable/quickview.png Binary files differnew file mode 100644 index 0000000..cefd851 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/quickview.png diff --git a/samples/PhotoEditor/res/drawable/quickview_on.png b/samples/PhotoEditor/res/drawable/quickview_on.png Binary files differnew file mode 100644 index 0000000..eb7c77f --- /dev/null +++ b/samples/PhotoEditor/res/drawable/quickview_on.png diff --git a/samples/PhotoEditor/res/drawable/redeye_off.png b/samples/PhotoEditor/res/drawable/redeye_off.png Binary files differnew file mode 100644 index 0000000..ec21a96 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/redeye_off.png diff --git a/samples/PhotoEditor/res/drawable/redeye_on.png b/samples/PhotoEditor/res/drawable/redeye_on.png Binary files differnew file mode 100644 index 0000000..df83f11 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/redeye_on.png diff --git a/samples/PhotoEditor/res/drawable/redo.png b/samples/PhotoEditor/res/drawable/redo.png Binary files differnew file mode 100644 index 0000000..780871e --- /dev/null +++ b/samples/PhotoEditor/res/drawable/redo.png diff --git a/samples/PhotoEditor/res/drawable/rotate_off.png b/samples/PhotoEditor/res/drawable/rotate_off.png Binary files differnew file mode 100644 index 0000000..153d733 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/rotate_off.png diff --git a/samples/PhotoEditor/res/drawable/rotate_on.png b/samples/PhotoEditor/res/drawable/rotate_on.png Binary files differnew file mode 100644 index 0000000..c2e26c7 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/rotate_on.png diff --git a/samples/PhotoEditor/res/drawable/saturation_off.png b/samples/PhotoEditor/res/drawable/saturation_off.png Binary files differnew file mode 100644 index 0000000..d151d5c --- /dev/null +++ b/samples/PhotoEditor/res/drawable/saturation_off.png diff --git a/samples/PhotoEditor/res/drawable/saturation_on.png b/samples/PhotoEditor/res/drawable/saturation_on.png Binary files differnew file mode 100644 index 0000000..415305d --- /dev/null +++ b/samples/PhotoEditor/res/drawable/saturation_on.png diff --git a/samples/PhotoEditor/res/drawable/saveas.png b/samples/PhotoEditor/res/drawable/saveas.png Binary files differnew file mode 100644 index 0000000..5f572ac --- /dev/null +++ b/samples/PhotoEditor/res/drawable/saveas.png diff --git a/samples/PhotoEditor/res/drawable/scale_wheel_background.png b/samples/PhotoEditor/res/drawable/scale_wheel_background.png Binary files differnew file mode 100644 index 0000000..c3dc5c8 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/scale_wheel_background.png diff --git a/samples/PhotoEditor/res/drawable/sepia_off.png b/samples/PhotoEditor/res/drawable/sepia_off.png Binary files differnew file mode 100644 index 0000000..236b990 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/sepia_off.png diff --git a/samples/PhotoEditor/res/drawable/sepia_on.png b/samples/PhotoEditor/res/drawable/sepia_on.png Binary files differnew file mode 100644 index 0000000..9fb3b66 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/sepia_on.png diff --git a/samples/PhotoEditor/res/drawable/shadow_off.png b/samples/PhotoEditor/res/drawable/shadow_off.png Binary files differnew file mode 100644 index 0000000..e3caa44 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/shadow_off.png diff --git a/samples/PhotoEditor/res/drawable/shadow_on.png b/samples/PhotoEditor/res/drawable/shadow_on.png Binary files differnew file mode 100644 index 0000000..5d7e0da --- /dev/null +++ b/samples/PhotoEditor/res/drawable/shadow_on.png diff --git a/samples/PhotoEditor/res/drawable/sharpen_off.png b/samples/PhotoEditor/res/drawable/sharpen_off.png Binary files differnew file mode 100644 index 0000000..89ce896 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/sharpen_off.png diff --git a/samples/PhotoEditor/res/drawable/sharpen_on.png b/samples/PhotoEditor/res/drawable/sharpen_on.png Binary files differnew file mode 100644 index 0000000..dc030fa --- /dev/null +++ b/samples/PhotoEditor/res/drawable/sharpen_on.png diff --git a/samples/PhotoEditor/res/drawable/softfocus_off.png b/samples/PhotoEditor/res/drawable/softfocus_off.png Binary files differnew file mode 100644 index 0000000..e7b63f2 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/softfocus_off.png diff --git a/samples/PhotoEditor/res/drawable/softfocus_on.png b/samples/PhotoEditor/res/drawable/softfocus_on.png Binary files differnew file mode 100644 index 0000000..cfd23c5 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/softfocus_on.png diff --git a/samples/PhotoEditor/res/drawable/straighten_off.png b/samples/PhotoEditor/res/drawable/straighten_off.png Binary files differnew file mode 100644 index 0000000..d558ed8 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/straighten_off.png diff --git a/samples/PhotoEditor/res/drawable/straighten_on.png b/samples/PhotoEditor/res/drawable/straighten_on.png Binary files differnew file mode 100644 index 0000000..7a81448 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/straighten_on.png diff --git a/samples/PhotoEditor/res/drawable/tint_off.png b/samples/PhotoEditor/res/drawable/tint_off.png Binary files differnew file mode 100644 index 0000000..6a6bb33 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/tint_off.png diff --git a/samples/PhotoEditor/res/drawable/tint_on.png b/samples/PhotoEditor/res/drawable/tint_on.png Binary files differnew file mode 100644 index 0000000..9ade695 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/tint_on.png diff --git a/samples/PhotoEditor/res/drawable/undo.png b/samples/PhotoEditor/res/drawable/undo.png Binary files differnew file mode 100644 index 0000000..2fa3df6 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/undo.png diff --git a/samples/PhotoEditor/res/drawable/vignette_off.png b/samples/PhotoEditor/res/drawable/vignette_off.png Binary files differnew file mode 100644 index 0000000..e529563 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/vignette_off.png diff --git a/samples/PhotoEditor/res/drawable/vignette_on.png b/samples/PhotoEditor/res/drawable/vignette_on.png Binary files differnew file mode 100644 index 0000000..e5d762d --- /dev/null +++ b/samples/PhotoEditor/res/drawable/vignette_on.png diff --git a/samples/PhotoEditor/res/drawable/warmify_off.png b/samples/PhotoEditor/res/drawable/warmify_off.png Binary files differnew file mode 100644 index 0000000..770746a --- /dev/null +++ b/samples/PhotoEditor/res/drawable/warmify_off.png diff --git a/samples/PhotoEditor/res/drawable/warmify_on.png b/samples/PhotoEditor/res/drawable/warmify_on.png Binary files differnew file mode 100644 index 0000000..443fb7a --- /dev/null +++ b/samples/PhotoEditor/res/drawable/warmify_on.png diff --git a/samples/PhotoEditor/res/drawable/wheel_knot_normal.png b/samples/PhotoEditor/res/drawable/wheel_knot_normal.png Binary files differnew file mode 100644 index 0000000..5a3b27d --- /dev/null +++ b/samples/PhotoEditor/res/drawable/wheel_knot_normal.png diff --git a/samples/PhotoEditor/res/drawable/wheel_knot_pressed.png b/samples/PhotoEditor/res/drawable/wheel_knot_pressed.png Binary files differnew file mode 100644 index 0000000..3b95aa5 --- /dev/null +++ b/samples/PhotoEditor/res/drawable/wheel_knot_pressed.png diff --git a/samples/PhotoEditor/res/drawable/wheel_knot_selector.xml b/samples/PhotoEditor/res/drawable/wheel_knot_selector.xml new file mode 100644 index 0000000..52ac39e --- /dev/null +++ b/samples/PhotoEditor/res/drawable/wheel_knot_selector.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="false" android:drawable="@drawable/wheel_knot_normal" /> + <item android:state_pressed="true" android:drawable="@drawable/wheel_knot_pressed" /> +</selector> diff --git a/samples/PhotoEditor/res/layout/artistic_effects.xml b/samples/PhotoEditor/res/layout/artistic_effects.xml new file mode 100644 index 0000000..1d34450 --- /dev/null +++ b/samples/PhotoEditor/res/layout/artistic_effects.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<com.android.photoeditor.EffectsGroup + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:photoeditor="http://schemas.android.com/apk/res/com.android.photoeditor" + style="@style/EffectsBarLinearLayout"> + + <FrameLayout android:id="@+id/group_header" style="@style/GroupHeader"> + + <TextView android:text="@string/artistic_group" style="@style/GroupLabel"/> + <ImageView android:id="@+id/group_arrow" style="@style/GroupArrow"/> + + </FrameLayout> + + <LinearLayout android:id="@+id/grouped_effects" style="@style/GroupContent"> + + <LinearLayout style="@style/Effect" android:id="@+id/fisheye_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/fisheye_modes" + photoeditor:icons="@array/fisheye_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/fisheye" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/vignette_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/vignette_modes" + photoeditor:icons="@array/vignette_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/vignette" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/crossprocess_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/crossprocess_modes" + photoeditor:icons="@array/crossprocess_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/crossprocess" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/documentary_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/documentary_modes" + photoeditor:icons="@array/documentary_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/documentary" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/lomoish_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/lomoish_modes" + photoeditor:icons="@array/lomoish_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/lomoish" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/grain_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/grain_modes" + photoeditor:icons="@array/grain_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/grain" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/posterize_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/posterize_modes" + photoeditor:icons="@array/posterize_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/posterize" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/doodle_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/doodle_modes" + photoeditor:icons="@array/doodle_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/doodle" + style="@style/EffectLabel"/> + </LinearLayout> + + </LinearLayout> +</com.android.photoeditor.EffectsGroup> diff --git a/samples/PhotoEditor/res/layout/color_effects.xml b/samples/PhotoEditor/res/layout/color_effects.xml new file mode 100644 index 0000000..7fe0669 --- /dev/null +++ b/samples/PhotoEditor/res/layout/color_effects.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<com.android.photoeditor.EffectsGroup + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:photoeditor="http://schemas.android.com/apk/res/com.android.photoeditor" + style="@style/EffectsBarLinearLayout"> + + <FrameLayout android:id="@+id/group_header" style="@style/GroupHeader"> + + <TextView android:text="@string/color_group" style="@style/GroupLabel"/> + <ImageView android:id="@+id/group_arrow" style="@style/GroupArrow"/> + + </FrameLayout> + + <LinearLayout android:id="@+id/grouped_effects" style="@style/GroupContent"> + + <LinearLayout style="@style/Effect" android:id="@+id/warmify_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/warmify_modes" + photoeditor:icons="@array/warmify_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/warmify" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/sepia_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/sepia_modes" + photoeditor:icons="@array/sepia_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/sepia" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/grayscale_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/grayscale_modes" + photoeditor:icons="@array/grayscale_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/grayscale" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/negative_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/negative_modes" + photoeditor:icons="@array/negative_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/negative" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/duotone_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/duotone_modes" + photoeditor:icons="@array/duotone_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/duotone" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/tint_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/tint_modes" + photoeditor:icons="@array/tint_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/tint" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/temperature_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/temperature_modes" + photoeditor:icons="@array/temperature_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/temperature" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/saturation_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/saturation_modes" + photoeditor:icons="@array/saturation_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/saturation" + style="@style/EffectLabel"/> + </LinearLayout> + + </LinearLayout> +</com.android.photoeditor.EffectsGroup> diff --git a/samples/PhotoEditor/res/layout/exposure_effects.xml b/samples/PhotoEditor/res/layout/exposure_effects.xml new file mode 100644 index 0000000..b1d3476 --- /dev/null +++ b/samples/PhotoEditor/res/layout/exposure_effects.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<com.android.photoeditor.EffectsGroup + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:photoeditor="http://schemas.android.com/apk/res/com.android.photoeditor" + style="@style/EffectsBarLinearLayout"> + + <FrameLayout android:id="@+id/group_header" style="@style/GroupHeader"> + + <TextView android:text="@string/exposure_group" style="@style/GroupLabel"/> + <ImageView android:id="@+id/group_arrow" style="@style/GroupArrow"/> + + </FrameLayout> + + <LinearLayout android:id="@+id/grouped_effects" style="@style/GroupContent"> + + <LinearLayout style="@style/Effect" android:id="@+id/filllight_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/filllight_modes" + photoeditor:icons="@array/filllight_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/filllight" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/highlight_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/highlight_modes" + photoeditor:icons="@array/highlight_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/highlight" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/shadow_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/shadow_modes" + photoeditor:icons="@array/shadow_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/shadow" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/autofix_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/autofix_modes" + photoeditor:icons="@array/autofix_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/autofix" + style="@style/EffectLabel"/> + </LinearLayout> + + </LinearLayout> +</com.android.photoeditor.EffectsGroup> diff --git a/samples/PhotoEditor/res/layout/fix_effects.xml b/samples/PhotoEditor/res/layout/fix_effects.xml new file mode 100644 index 0000000..7892646 --- /dev/null +++ b/samples/PhotoEditor/res/layout/fix_effects.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<com.android.photoeditor.EffectsGroup + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:photoeditor="http://schemas.android.com/apk/res/com.android.photoeditor" + style="@style/EffectsBarLinearLayout"> + + <FrameLayout android:id="@+id/group_header" style="@style/GroupHeader"> + + <TextView android:text="@string/fix_group" style="@style/GroupLabel"/> + <ImageView android:id="@+id/group_arrow" style="@style/GroupArrow"/> + + </FrameLayout> + + <LinearLayout android:id="@+id/grouped_effects" style="@style/GroupContent"> + + <LinearLayout style="@style/Effect" android:id="@+id/crop_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/crop_modes" + photoeditor:icons="@array/crop_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/crop" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/rotate_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/rotate_modes" + photoeditor:icons="@array/rotate_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/rotate" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/straighten_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/straighten_modes" + photoeditor:icons="@array/straighten_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/straighten" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/flip_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/flip_modes" + photoeditor:icons="@array/flip_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/flip" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/redeye_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/redeye_modes" + photoeditor:icons="@array/redeye_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/redeye" + style="@style/EffectLabel"/> + </LinearLayout> + <LinearLayout style="@style/Effect" android:id="@+id/sharpen_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/sharpen_modes" + photoeditor:icons="@array/sharpen_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/sharpen" + style="@style/EffectLabel"/> + </LinearLayout> + <!--<LinearLayout style="@style/Effect" android:id="@+id/softfocus_effect"> + <com.android.photoeditor.IconIndicator + android:id="@+id/effect_button" + style="@style/EffectIcon" + photoeditor:modes="@array/softfocus_modes" + photoeditor:icons="@array/softfocus_icons"/> + <TextView + android:id="@+id/effect_label" + android:text="@string/softfocus" + style="@style/EffectLabel"/> + </LinearLayout>--> + + </LinearLayout> +</com.android.photoeditor.EffectsGroup> diff --git a/samples/PhotoEditor/res/layout/main.xml b/samples/PhotoEditor/res/layout/main.xml new file mode 100644 index 0000000..dee7f50 --- /dev/null +++ b/samples/PhotoEditor/res/layout/main.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<com.android.photoeditor.Toolbar + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/toolbar" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <com.android.photoeditor.PhotoView + android:id="@+id/photo_view" + android:layout_width="fill_parent" + android:layout_height="fill_parent"/> + + <com.android.photoeditor.actions.TouchView + android:id="@+id/touch_view" + style="@style/FullscreenToolView"/> + <com.android.photoeditor.actions.DoodleView + android:id="@+id/doodle_view" + style="@style/FullscreenToolView"/> + <com.android.photoeditor.actions.RotateView + android:id="@+id/rotate_view" + style="@style/FullscreenToolView"/> + <com.android.photoeditor.actions.CropView + android:id="@+id/crop_view" + style="@style/FullscreenToolView"/> + <com.android.photoeditor.actions.ScaleWheel + android:id="@+id/scale_wheel" + android:tag="fadeOnIdle" + style="@style/Wheel"/> + <com.android.photoeditor.actions.ColorWheel + android:id="@+id/color_wheel" + android:tag="fadeOnIdle" + style="@style/Wheel"/> + + <com.android.photoeditor.EffectsBar + android:id="@+id/effects_bar" + android:layout_below="@+id/action_bar" + style="@style/EffectsBar"> + + <LinearLayout + android:id="@+id/effects_container" + style="@style/EffectsBarLinearLayout"> + + <include layout="@layout/exposure_effects"/> + <include layout="@layout/fix_effects"/> + <include layout="@layout/artistic_effects"/> + <include layout="@layout/color_effects"/> + </LinearLayout> + </com.android.photoeditor.EffectsBar> + + <com.android.photoeditor.ActionBar + android:id="@+id/action_bar" + android:tag="fadeOnIdle" + style="@style/ActionBar"> + + <RelativeLayout style="@style/ActionBarTranslucent"> + <LinearLayout style="@style/ActionBarLinearLayout"> + + <LinearLayout + android:id="@+id/action_bar_back" + style="@style/ActionBarBackLinearLayout"> + <ImageView style="@style/ActionBarArrow"/> + <ImageView style="@style/ActionBarIcon"/> + </LinearLayout> + + <TextView android:id="@+id/action_effect_name" style="@style/ActionBarText"/> + </LinearLayout> + + <LinearLayout + style="@style/ActionBarLinearLayout" + android:layout_alignParentRight="true"> + + <ImageButton + android:id="@+id/save_button" + style="@style/ActionButton" + android:src="@drawable/saveas"/> + <ImageButton + android:id="@+id/undo_button" + style="@style/ActionButton" + android:src="@drawable/undo"/> + <ImageButton + android:id="@+id/redo_button" + style="@style/ActionButton" + android:src="@drawable/redo"/> + <ImageButton + android:id="@+id/quickview_button" + style="@style/RightmostActionButton" + android:src="@drawable/quickview"/> + </LinearLayout> + </RelativeLayout> + + <ImageButton + android:id="@+id/quickview_on_button" + style="@style/RightmostActionButton" + android:layout_gravity="center_vertical|right" + android:src="@drawable/quickview_on"/> + + </com.android.photoeditor.ActionBar> +</com.android.photoeditor.Toolbar> diff --git a/samples/PhotoEditor/res/values-ar/strings.xml b/samples/PhotoEditor/res/values-ar/strings.xml new file mode 100644 index 0000000..4405989 --- /dev/null +++ b/samples/PhotoEditor/res/values-ar/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"تعذر تحميل الصورة للتعديل"</string> + <string name="saving_failure" msgid="3116717307036082369">"حدث خطأ أثناء الحفظ"</string> + <string name="photo_saved" msgid="5093564498138145422">"تم حفظ <xliff:g id="FILENAME">%s</xliff:g>"</string> + <string name="save_photo" msgid="3125109368779997862">"هل تريد حفظ الصورة التي تم تعديلها؟"</string> + <string name="yes" msgid="5402582493291792293">"نعم"</string> + <string name="no" msgid="5595408018304861875">"لا"</string> + <string name="cancel" msgid="6286688759430767307">"إلغاء"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"صور معدلة"</string> + <string name="artistic_group" msgid="573091775825402562">"فني"</string> + <string name="color_group" msgid="3390757893475444688">"اللون"</string> + <string name="exposure_group" msgid="7019148007708100078">"التعرض للضوء"</string> + <string name="fix_group" msgid="971450155810247383">"إصلاح"</string> + <string name="autofix" msgid="1223859191856172755">"ضربة حظ"</string> + <string name="crossprocess" msgid="4173724489001742342">"معالجة متقاطعة"</string> + <string name="documentary" msgid="50396326708699797">"وثائقي"</string> + <string name="doodle" msgid="1686409894518940990">"رسومات مبتكرة"</string> + <string name="duotone" msgid="8145893940788467106">"درجة لونين"</string> + <string name="filllight" msgid="2644989991700022526">"إضاءة تكميلية"</string> + <string name="fisheye" msgid="6037488646928998921">"عين سمكة"</string> + <string name="flip" msgid="2357692401826287480">"عكس"</string> + <string name="grain" msgid="7487585304579789098">"تحبب الفيلم"</string> + <string name="grayscale" msgid="615169770671286699">"تدرج الرمادي"</string> + <string name="highlight" msgid="3902653944386623972">"لمحات"</string> + <string name="lomoish" msgid="7793824845892532976">"متعلق بـ Lomo"</string> + <string name="negative" msgid="1985508917342811252">"سلبي"</string> + <string name="posterize" msgid="4139212359561383385">"تتالٍ"</string> + <string name="redeye" msgid="4958448806369928239">"العين الحمراء"</string> + <string name="rotate" msgid="6607597269792373083">"تدوير"</string> + <string name="saturation" msgid="8621322012271169931">"تشبع اللون"</string> + <string name="sepia" msgid="7978093531824705601">"بني داكن"</string> + <string name="shadow" msgid="8235188588101973090">"ظلال"</string> + <string name="sharpen" msgid="8449662378104403230">"زيادة الحدة"</string> + <string name="softfocus" msgid="6334228862566408303">"تركيز ضعيف"</string> + <string name="straighten" msgid="5217801513491493491">"تسوية"</string> + <string name="temperature" msgid="3589958696423284897">"درجة الحرارة"</string> + <string name="tint" msgid="154435943863418434">"تلوين خفيف"</string> + <string name="vignette" msgid="7648125924662648282">"نقوش صورة نصفية"</string> + <string name="warmify" msgid="2404474974251014984">"زيادة دفء اللون"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"اسحب الصورة لإنشاء رسومات مبتكرة"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"اسحب الصورة لقلبها"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"انقر لإزالة الأعين الحمراء"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"اسحب الصورة لتدويرها"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"اسحب الصورة لتسويتها"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-bg/strings.xml b/samples/PhotoEditor/res/values-bg/strings.xml new file mode 100644 index 0000000..f28f7d7 --- /dev/null +++ b/samples/PhotoEditor/res/values-bg/strings.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Снимката не може да бъде заредена за редактиране"</string> + <string name="saving_failure" msgid="3116717307036082369">"Възникна проблем при запазването"</string> + <string name="photo_saved" msgid="5093564498138145422">"„<xliff:g id="FILENAME">%s</xliff:g>“ е запазено"</string> + <string name="save_photo" msgid="3125109368779997862">"Да се запази ли редактираната снимка?"</string> + <string name="yes" msgid="5402582493291792293">"Да"</string> + <string name="no" msgid="5595408018304861875">"Нe"</string> + <string name="cancel" msgid="6286688759430767307">"Отказ"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Редактирани"</string> + <string name="artistic_group" msgid="573091775825402562">"Художеств."</string> + <string name="color_group" msgid="3390757893475444688">"Цвят"</string> + <string name="exposure_group" msgid="7019148007708100078">"Експонация"</string> + <string name="fix_group" msgid="971450155810247383">"Корекция"</string> + <string name="autofix" msgid="1223859191856172755">"С късмет"</string> + <string name="crossprocess" msgid="4173724489001742342">"Кроспроцес"</string> + <string name="documentary" msgid="50396326708699797">"Документален филм"</string> + <string name="doodle" msgid="1686409894518940990">"Рисунка"</string> + <string name="duotone" msgid="8145893940788467106">"В два цвята"</string> + <string name="filllight" msgid="2644989991700022526">"Запълв. светл."</string> + <string name="fisheye" msgid="6037488646928998921">"Рибешко око"</string> + <string name="flip" msgid="2357692401826287480">"Обръщане"</string> + <string name="grain" msgid="7487585304579789098">"Зърнистост"</string> + <string name="grayscale" msgid="615169770671286699">"Сива скала"</string> + <string name="highlight" msgid="3902653944386623972">"Светли участъци"</string> + <string name="lomoish" msgid="7793824845892532976">"Като „Ломо“"</string> + <string name="negative" msgid="1985508917342811252">"Негатив"</string> + <string name="posterize" msgid="4139212359561383385">"Плакат"</string> + <string name="redeye" msgid="4958448806369928239">"Червени очи"</string> + <string name="rotate" msgid="6607597269792373083">"Завъртане"</string> + <string name="saturation" msgid="8621322012271169931">"Насищане"</string> + <string name="sepia" msgid="7978093531824705601">"Сепия"</string> + <string name="shadow" msgid="8235188588101973090">"Тъмни участъци"</string> + <string name="sharpen" msgid="8449662378104403230">"Отчетливост"</string> + <string name="softfocus" msgid="6334228862566408303">"Мек фокус"</string> + <string name="straighten" msgid="5217801513491493491">"Изправяне"</string> + <string name="temperature" msgid="3589958696423284897">"Температура"</string> + <string name="tint" msgid="154435943863418434">"Нюансиране"</string> + <string name="vignette" msgid="7648125924662648282">"Винетиране"</string> + <string name="warmify" msgid="2404474974251014984">"Затопляне"</string> + <!-- no translation found for doodle_tooltip (2902117272374362915) --> + <skip /> + <!-- no translation found for flip_tooltip (2700943256714731737) --> + <skip /> + <!-- no translation found for redeye_tooltip (9112774042113471358) --> + <skip /> + <!-- no translation found for rotate_tooltip (7008602969130734229) --> + <skip /> + <!-- no translation found for straighten_tooltip (4846317027139212339) --> + <skip /> +</resources> diff --git a/samples/PhotoEditor/res/values-ca/strings.xml b/samples/PhotoEditor/res/values-ca/strings.xml new file mode 100644 index 0000000..0dcb2e6 --- /dev/null +++ b/samples/PhotoEditor/res/values-ca/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Estudi de fotografia"</string> + <string name="loading_failure" msgid="8575831322115054185">"La foto no es pot carregar per editar-la"</string> + <string name="saving_failure" msgid="3116717307036082369">"S\'ha produït un problema en desar"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> desada"</string> + <string name="save_photo" msgid="3125109368779997862">"Vols desar la foto editada?"</string> + <string name="yes" msgid="5402582493291792293">"Sí"</string> + <string name="no" msgid="5595408018304861875">"No"</string> + <string name="cancel" msgid="6286688759430767307">"Cancel·la"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Editades"</string> + <string name="artistic_group" msgid="573091775825402562">"Artístics"</string> + <string name="color_group" msgid="3390757893475444688">"Color"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposició"</string> + <string name="fix_group" msgid="971450155810247383">"Correcció"</string> + <string name="autofix" msgid="1223859191856172755">"Correcc. autom."</string> + <string name="crossprocess" msgid="4173724489001742342">"Procés creuat"</string> + <string name="documentary" msgid="50396326708699797">"Documental"</string> + <string name="doodle" msgid="1686409894518940990">"Gargots"</string> + <string name="duotone" msgid="8145893940788467106">"Dos tons"</string> + <string name="filllight" msgid="2644989991700022526">"Retroil·lumin."</string> + <string name="fisheye" msgid="6037488646928998921">"Ull de peix"</string> + <string name="flip" msgid="2357692401826287480">"Inversió"</string> + <string name="grain" msgid="7487585304579789098">"Gra pel·lícula"</string> + <string name="grayscale" msgid="615169770671286699">"Escala grisos"</string> + <string name="highlight" msgid="3902653944386623972">"Realçaments"</string> + <string name="lomoish" msgid="7793824845892532976">"Estil Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negatiu"</string> + <string name="posterize" msgid="4139212359561383385">"Posterització"</string> + <string name="redeye" msgid="4958448806369928239">"Ulls vermells"</string> + <string name="rotate" msgid="6607597269792373083">"Gir"</string> + <string name="saturation" msgid="8621322012271169931">"Saturació"</string> + <string name="sepia" msgid="7978093531824705601">"Sèpia"</string> + <string name="shadow" msgid="8235188588101973090">"Ombres"</string> + <string name="sharpen" msgid="8449662378104403230">"Nitidesa"</string> + <string name="softfocus" msgid="6334228862566408303">"Focus suau"</string> + <string name="straighten" msgid="5217801513491493491">"Redreçament"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Tint"</string> + <string name="vignette" msgid="7648125924662648282">"Vinyeta"</string> + <string name="warmify" msgid="2404474974251014984">"Calidesa"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Arrossega el cursor sobre la foto per dibuixar"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Arrossega la foto per invertir-la"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Toca per eliminar els ulls vermells"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Arrossega la foto per girar-la"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Arrossega la foto per redreçar-la"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-cs/strings.xml b/samples/PhotoEditor/res/values-cs/strings.xml new file mode 100644 index 0000000..df0b474 --- /dev/null +++ b/samples/PhotoEditor/res/values-cs/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Fotografii nelze načíst k úpravám"</string> + <string name="saving_failure" msgid="3116717307036082369">"Při ukládání došlo k problému"</string> + <string name="photo_saved" msgid="5093564498138145422">"Fotografie <xliff:g id="FILENAME">%s</xliff:g> byla uložena"</string> + <string name="save_photo" msgid="3125109368779997862">"Chcete upravenou fotografii uložit?"</string> + <string name="yes" msgid="5402582493291792293">"Ano"</string> + <string name="no" msgid="5595408018304861875">"Ne"</string> + <string name="cancel" msgid="6286688759430767307">"Zrušit"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Upraveno"</string> + <string name="artistic_group" msgid="573091775825402562">"Umělecké"</string> + <string name="color_group" msgid="3390757893475444688">"Barva"</string> + <string name="exposure_group" msgid="7019148007708100078">"Expozice"</string> + <string name="fix_group" msgid="971450155810247383">"Korekce"</string> + <string name="autofix" msgid="1223859191856172755">"Zkusím štěstí"</string> + <string name="crossprocess" msgid="4173724489001742342">"Křížové zpracování"</string> + <string name="documentary" msgid="50396326708699797">"Dokument"</string> + <string name="doodle" msgid="1686409894518940990">"Kreslení"</string> + <string name="duotone" msgid="8145893940788467106">"Duo-tone"</string> + <string name="filllight" msgid="2644989991700022526">"Zadní osvětlení"</string> + <string name="fisheye" msgid="6037488646928998921">"Rybí oko"</string> + <string name="flip" msgid="2357692401826287480">"Převrácení"</string> + <string name="grain" msgid="7487585304579789098">"Zrnitý film"</string> + <string name="grayscale" msgid="615169770671286699">"Stupně šedi"</string> + <string name="highlight" msgid="3902653944386623972">"Přisvícení"</string> + <string name="lomoish" msgid="7793824845892532976">"LOMO"</string> + <string name="negative" msgid="1985508917342811252">"Negativ"</string> + <string name="posterize" msgid="4139212359561383385">"Posterizace"</string> + <string name="redeye" msgid="4958448806369928239">"Červené oči"</string> + <string name="rotate" msgid="6607597269792373083">"Otočení"</string> + <string name="saturation" msgid="8621322012271169931">"Sytost"</string> + <string name="sepia" msgid="7978093531824705601">"Sépiové barvy"</string> + <string name="shadow" msgid="8235188588101973090">"Stíny"</string> + <string name="sharpen" msgid="8449662378104403230">"Zaostření"</string> + <string name="softfocus" msgid="6334228862566408303">"Jemné rozostření"</string> + <string name="straighten" msgid="5217801513491493491">"Vyrovnání"</string> + <string name="temperature" msgid="3589958696423284897">"Teplota"</string> + <string name="tint" msgid="154435943863418434">"Tónování"</string> + <string name="vignette" msgid="7648125924662648282">"Medailonek"</string> + <string name="warmify" msgid="2404474974251014984">"Teplejší barvy"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Na fotografii můžete kreslit prstem"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Táhnutím prstem fotografii převrátíte"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Klepnutím odstraníte červené oči"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Táhnutím prstem fotografii otočíte"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Táhnutím prstem fotografii narovnáte"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-da/strings.xml b/samples/PhotoEditor/res/values-da/strings.xml new file mode 100644 index 0000000..0dd390f --- /dev/null +++ b/samples/PhotoEditor/res/values-da/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Fotostudie"</string> + <string name="loading_failure" msgid="8575831322115054185">"Billedet kan ikke indlæses til redigering"</string> + <string name="saving_failure" msgid="3116717307036082369">"Der opstod et problem ved lagring"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> er gemt"</string> + <string name="save_photo" msgid="3125109368779997862">"Vil du gemme det redigerede billede?"</string> + <string name="yes" msgid="5402582493291792293">"Ja"</string> + <string name="no" msgid="5595408018304861875">"Nej"</string> + <string name="cancel" msgid="6286688759430767307">"Annuller"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Redigeret"</string> + <string name="artistic_group" msgid="573091775825402562">"Kunstnerisk"</string> + <string name="color_group" msgid="3390757893475444688">"Farve"</string> + <string name="exposure_group" msgid="7019148007708100078">"Eksponering"</string> + <string name="fix_group" msgid="971450155810247383">"Ret"</string> + <string name="autofix" msgid="1223859191856172755">"Prøv lykken"</string> + <string name="crossprocess" msgid="4173724489001742342">"Krydsfremkald"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentar"</string> + <string name="doodle" msgid="1686409894518940990">"Krusedulle"</string> + <string name="duotone" msgid="8145893940788467106">"Tofarvet"</string> + <string name="filllight" msgid="2644989991700022526">"Oplys mørke"</string> + <string name="fisheye" msgid="6037488646928998921">"Fiskeøje"</string> + <string name="flip" msgid="2357692401826287480">"Vend"</string> + <string name="grain" msgid="7487585304579789098">"Filmkorn"</string> + <string name="grayscale" msgid="615169770671286699">"Gråtoner"</string> + <string name="highlight" msgid="3902653944386623972">"Fremhævning"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo-effekt"</string> + <string name="negative" msgid="1985508917342811252">"Negativ"</string> + <string name="posterize" msgid="4139212359561383385">"Posterisering"</string> + <string name="redeye" msgid="4958448806369928239">"Røde øjne"</string> + <string name="rotate" msgid="6607597269792373083">"Roter"</string> + <string name="saturation" msgid="8621322012271169931">"Mætning"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Skygger"</string> + <string name="sharpen" msgid="8449662378104403230">"Gør skarpere"</string> + <string name="softfocus" msgid="6334228862566408303">"Blødt fokus"</string> + <string name="straighten" msgid="5217801513491493491">"Ret op"</string> + <string name="temperature" msgid="3589958696423284897">"Farvetemperatur"</string> + <string name="tint" msgid="154435943863418434">"Nuance"</string> + <string name="vignette" msgid="7648125924662648282">"Vignet"</string> + <string name="warmify" msgid="2404474974251014984">"Gør varmere"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Tegn på billedet for at lave kruseduller"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Træk billedet for at vende det"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Tryk for at fjerne røde øjne"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Træk billedet for at rotere det"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Træk i billedet for at rette det op"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-de/strings.xml b/samples/PhotoEditor/res/values-de/strings.xml new file mode 100644 index 0000000..0e5df5f --- /dev/null +++ b/samples/PhotoEditor/res/values-de/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Laden des Fotos zum Bearbeiten nicht möglich."</string> + <string name="saving_failure" msgid="3116717307036082369">"Beim Speichern ist ein Problem aufgetreten."</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> gespeichert"</string> + <string name="save_photo" msgid="3125109368779997862">"Bearbeitetes Foto speichern?"</string> + <string name="yes" msgid="5402582493291792293">"Ja"</string> + <string name="no" msgid="5595408018304861875">"Nein"</string> + <string name="cancel" msgid="6286688759430767307">"Abbrechen"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Bearbeitet"</string> + <string name="artistic_group" msgid="573091775825402562">"Kunstvoll"</string> + <string name="color_group" msgid="3390757893475444688">"Farbe"</string> + <string name="exposure_group" msgid="7019148007708100078">"Belichtung"</string> + <string name="fix_group" msgid="971450155810247383">"Korrektur"</string> + <string name="autofix" msgid="1223859191856172755">"Gute Stimmung"</string> + <string name="crossprocess" msgid="4173724489001742342">"Cross-Entwickl."</string> + <string name="documentary" msgid="50396326708699797">"Dokumentation"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Duoton"</string> + <string name="filllight" msgid="2644989991700022526">"Aufhellen"</string> + <string name="fisheye" msgid="6037488646928998921">"Fischauge"</string> + <string name="flip" msgid="2357692401826287480">"Spiegeln"</string> + <string name="grain" msgid="7487585304579789098">"Filmkörnung"</string> + <string name="grayscale" msgid="615169770671286699">"Graustufen"</string> + <string name="highlight" msgid="3902653944386623972">"Highlights"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomoesk"</string> + <string name="negative" msgid="1985508917342811252">"Negativ"</string> + <string name="posterize" msgid="4139212359561383385">"Tontrennung"</string> + <string name="redeye" msgid="4958448806369928239">"Rote Augen"</string> + <string name="rotate" msgid="6607597269792373083">"Drehen"</string> + <string name="saturation" msgid="8621322012271169931">"Sättigung"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Schatten"</string> + <string name="sharpen" msgid="8449662378104403230">"Scharf stellen"</string> + <string name="softfocus" msgid="6334228862566408303">"Weichzeichnen"</string> + <string name="straighten" msgid="5217801513491493491">"Ausrichten"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatur"</string> + <string name="tint" msgid="154435943863418434">"Färbung"</string> + <string name="vignette" msgid="7648125924662648282">"Vignettierung"</string> + <string name="warmify" msgid="2404474974251014984">"Wärmer gestalten"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Zum Erstellen eines Doodles auf dem Foto zeichnen"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Foto ziehen, um es umzudrehen"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Zum Entfernen roter Augen tippen"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Foto ziehen, um es zu drehen"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Foto ziehen, um es zu strecken"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-el/strings.xml b/samples/PhotoEditor/res/values-el/strings.xml new file mode 100644 index 0000000..30651ba --- /dev/null +++ b/samples/PhotoEditor/res/values-el/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Δεν είναι δυνατή η φόρτωση της φωτογραφίας για επεξεργασία"</string> + <string name="saving_failure" msgid="3116717307036082369">"Παρουσιάστηκε πρόβλημα κατά την αποθήκευση"</string> + <string name="photo_saved" msgid="5093564498138145422">"Το <xliff:g id="FILENAME">%s</xliff:g> αποθηκεύτηκε"</string> + <string name="save_photo" msgid="3125109368779997862">"Αποθήκευση επεξεργασμένης φωτογραφίας;"</string> + <string name="yes" msgid="5402582493291792293">"Ναι"</string> + <string name="no" msgid="5595408018304861875">"Όχι"</string> + <string name="cancel" msgid="6286688759430767307">"Ακύρωση"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Επεξεργασμ."</string> + <string name="artistic_group" msgid="573091775825402562">"Καλλιτεχν."</string> + <string name="color_group" msgid="3390757893475444688">"Χρώμα"</string> + <string name="exposure_group" msgid="7019148007708100078">"Έκθεση"</string> + <string name="fix_group" msgid="971450155810247383">"Διόρθωση"</string> + <string name="autofix" msgid="1223859191856172755">"Νιώθω τυχερός"</string> + <string name="crossprocess" msgid="4173724489001742342">"Cross Process"</string> + <string name="documentary" msgid="50396326708699797">"Ντοκιμαντέρ"</string> + <string name="doodle" msgid="1686409894518940990">"Σκετσάκι"</string> + <string name="duotone" msgid="8145893940788467106">"Δύο τόνοι"</string> + <string name="filllight" msgid="2644989991700022526">"Γέμισμα με φως"</string> + <string name="fisheye" msgid="6037488646928998921">"Fisheye"</string> + <string name="flip" msgid="2357692401826287480">"Αναστροφή"</string> + <string name="grain" msgid="7487585304579789098">"Κόκκος φιλμ"</string> + <string name="grayscale" msgid="615169770671286699">"Κλίμακα του γκρι"</string> + <string name="highlight" msgid="3902653944386623972">"Επισημάνσεις"</string> + <string name="lomoish" msgid="7793824845892532976">"Φίλτρο lomo"</string> + <string name="negative" msgid="1985508917342811252">"Αρνητικό"</string> + <string name="posterize" msgid="4139212359561383385">"Ποστεροποίηση"</string> + <string name="redeye" msgid="4958448806369928239">"Κόκκινα μάτια"</string> + <string name="rotate" msgid="6607597269792373083">"Περιστροφή"</string> + <string name="saturation" msgid="8621322012271169931">"Κορεσμός"</string> + <string name="sepia" msgid="7978093531824705601">"Σέπια"</string> + <string name="shadow" msgid="8235188588101973090">"Σκιές"</string> + <string name="sharpen" msgid="8449662378104403230">"Όξυνση"</string> + <string name="softfocus" msgid="6334228862566408303">"Απαλή εστίαση"</string> + <string name="straighten" msgid="5217801513491493491">"Ευθυγράμμιση"</string> + <string name="temperature" msgid="3589958696423284897">"Θερμοκρασία"</string> + <string name="tint" msgid="154435943863418434">"Απόχρωση"</string> + <string name="vignette" msgid="7648125924662648282">"Βινιετάρισμα"</string> + <string name="warmify" msgid="2404474974251014984">"Ζεστή απόχρωση"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Σχεδιάστε στη φωτογραφία για να δημιουργήσετε ένα σκετσάκι"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Σύρετε τη φωτογραφία για να την αναστρέψετε"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Πατήστε για να αφαιρέσετε τα κόκκινα μάτια"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Σύρετε τη φωτογραφία για να την περιστρέψετε"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Σύρετε τη φωτογραφία για να την ευθυγραμμίσετε"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-en-rGB/strings.xml b/samples/PhotoEditor/res/values-en-rGB/strings.xml new file mode 100644 index 0000000..14df5a7 --- /dev/null +++ b/samples/PhotoEditor/res/values-en-rGB/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Cannot load the photo for editing"</string> + <string name="saving_failure" msgid="3116717307036082369">"A problem occurred during saving"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> saved"</string> + <string name="save_photo" msgid="3125109368779997862">"Save edited photo?"</string> + <string name="yes" msgid="5402582493291792293">"Yes"</string> + <string name="no" msgid="5595408018304861875">"No"</string> + <string name="cancel" msgid="6286688759430767307">"Cancel"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Edited"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistic"</string> + <string name="color_group" msgid="3390757893475444688">"Colour"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposure"</string> + <string name="fix_group" msgid="971450155810247383">"Fix"</string> + <string name="autofix" msgid="1223859191856172755">"Feel Lucky"</string> + <string name="crossprocess" msgid="4173724489001742342">"Cross-Process"</string> + <string name="documentary" msgid="50396326708699797">"Documentary"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Duo-tone"</string> + <string name="filllight" msgid="2644989991700022526">"Fill Light"</string> + <string name="fisheye" msgid="6037488646928998921">"Fisheye"</string> + <string name="flip" msgid="2357692401826287480">"Flip"</string> + <string name="grain" msgid="7487585304579789098">"Film Grain"</string> + <string name="grayscale" msgid="615169770671286699">"Grey Scale"</string> + <string name="highlight" msgid="3902653944386623972">"Highlights"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo-ish"</string> + <string name="negative" msgid="1985508917342811252">"Negative"</string> + <string name="posterize" msgid="4139212359561383385">"Posterise"</string> + <string name="redeye" msgid="4958448806369928239">"Red Eye"</string> + <string name="rotate" msgid="6607597269792373083">"Rotate"</string> + <string name="saturation" msgid="8621322012271169931">"Saturation"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Shadows"</string> + <string name="sharpen" msgid="8449662378104403230">"Sharpen"</string> + <string name="softfocus" msgid="6334228862566408303">"Soft Focus"</string> + <string name="straighten" msgid="5217801513491493491">"Straighten"</string> + <string name="temperature" msgid="3589958696423284897">"Temperature"</string> + <string name="tint" msgid="154435943863418434">"Tint"</string> + <string name="vignette" msgid="7648125924662648282">"Vignette"</string> + <string name="warmify" msgid="2404474974251014984">"Warmify"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Draw on photo to doodle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Drag photo to flip it"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Tap to remove red eyes"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Drag photo to rotate it"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Drag photo to straighten it"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-es-rUS/strings.xml b/samples/PhotoEditor/res/values-es-rUS/strings.xml new file mode 100644 index 0000000..02c54ef --- /dev/null +++ b/samples/PhotoEditor/res/values-es-rUS/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Estudio de fotografía"</string> + <string name="loading_failure" msgid="8575831322115054185">"No se puede cargar la foto para editarla"</string> + <string name="saving_failure" msgid="3116717307036082369">"Se produjo un problema al guardar"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> guardado"</string> + <string name="save_photo" msgid="3125109368779997862">"¿Guardar foto editada?"</string> + <string name="yes" msgid="5402582493291792293">"Sí"</string> + <string name="no" msgid="5595408018304861875">"No"</string> + <string name="cancel" msgid="6286688759430767307">"Cancelar"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Editadas"</string> + <string name="artistic_group" msgid="573091775825402562">"Artísticos"</string> + <string name="color_group" msgid="3390757893475444688">"Color"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposición."</string> + <string name="fix_group" msgid="971450155810247383">"Con arreglos"</string> + <string name="autofix" msgid="1223859191856172755">"Me siento con suerte"</string> + <string name="crossprocess" msgid="4173724489001742342">"Proceso cruzado"</string> + <string name="documentary" msgid="50396326708699797">"Documental"</string> + <string name="doodle" msgid="1686409894518940990">"Garabatear"</string> + <string name="duotone" msgid="8145893940788467106">"Dos tonos"</string> + <string name="filllight" msgid="2644989991700022526">"Aumentar brillo"</string> + <string name="fisheye" msgid="6037488646928998921">"Ojo de pez"</string> + <string name="flip" msgid="2357692401826287480">"Cambiar"</string> + <string name="grain" msgid="7487585304579789098">"Grano de la película"</string> + <string name="grayscale" msgid="615169770671286699">"Escala de grises"</string> + <string name="highlight" msgid="3902653944386623972">"Destacadas"</string> + <string name="lomoish" msgid="7793824845892532976">"Estilo Lomo"</string> + <string name="negative" msgid="1985508917342811252">"negativo"</string> + <string name="posterize" msgid="4139212359561383385">"Posterizar"</string> + <string name="redeye" msgid="4958448806369928239">"Ojos rojos"</string> + <string name="rotate" msgid="6607597269792373083">"Girar"</string> + <string name="saturation" msgid="8621322012271169931">"Saturación"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Sombras"</string> + <string name="sharpen" msgid="8449662378104403230">"Mejorar nitidez"</string> + <string name="softfocus" msgid="6334228862566408303">"Desenfocar"</string> + <string name="straighten" msgid="5217801513491493491">"Enderezar"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Matiz"</string> + <string name="vignette" msgid="7648125924662648282">"Viñeta"</string> + <string name="warmify" msgid="2404474974251014984">"Más calidez"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Dibuja en la foto para hacer garabatos"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Arrastra la foto para darla vuelta"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Toca para eliminar los ojos rojos"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Arrastra la foto para hacerla girar"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Arrastra la foto para enderezarla"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-es/strings.xml b/samples/PhotoEditor/res/values-es/strings.xml new file mode 100644 index 0000000..08b808e --- /dev/null +++ b/samples/PhotoEditor/res/values-es/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"No se puede cargar la foto para editarla."</string> + <string name="saving_failure" msgid="3116717307036082369">"Error al guardar"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> guardado"</string> + <string name="save_photo" msgid="3125109368779997862">"¿Quieres guardar la foto editada?"</string> + <string name="yes" msgid="5402582493291792293">"Sí"</string> + <string name="no" msgid="5595408018304861875">"No"</string> + <string name="cancel" msgid="6286688759430767307">"Cancelar"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Editadas"</string> + <string name="artistic_group" msgid="573091775825402562">"Artísticos"</string> + <string name="color_group" msgid="3390757893475444688">"Color"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposición"</string> + <string name="fix_group" msgid="971450155810247383">"Fijos"</string> + <string name="autofix" msgid="1223859191856172755">"Con suerte"</string> + <string name="crossprocess" msgid="4173724489001742342">"Proceso cruzado"</string> + <string name="documentary" msgid="50396326708699797">"Documental"</string> + <string name="doodle" msgid="1686409894518940990">"Garabatos"</string> + <string name="duotone" msgid="8145893940788467106">"Dos tonos"</string> + <string name="filllight" msgid="2644989991700022526">"Luz de relleno"</string> + <string name="fisheye" msgid="6037488646928998921">"Ojo de pez"</string> + <string name="flip" msgid="2357692401826287480">"Dar la vuelta"</string> + <string name="grain" msgid="7487585304579789098">"Grano de película"</string> + <string name="grayscale" msgid="615169770671286699">"Escala de grises"</string> + <string name="highlight" msgid="3902653944386623972">"Reflejos"</string> + <string name="lomoish" msgid="7793824845892532976">"Estilo lomográfico"</string> + <string name="negative" msgid="1985508917342811252">"Negativo"</string> + <string name="posterize" msgid="4139212359561383385">"Posterizar"</string> + <string name="redeye" msgid="4958448806369928239">"Ojos rojos"</string> + <string name="rotate" msgid="6607597269792373083">"Girar"</string> + <string name="saturation" msgid="8621322012271169931">"Saturación"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Sombras"</string> + <string name="sharpen" msgid="8449662378104403230">"Enfocar"</string> + <string name="softfocus" msgid="6334228862566408303">"Desenfocar"</string> + <string name="straighten" msgid="5217801513491493491">"Enderezar"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Tinte"</string> + <string name="vignette" msgid="7648125924662648282">"Viñeta"</string> + <string name="warmify" msgid="2404474974251014984">"Más calidez"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Dibuja en la foto para hacer garabatos"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Arrastra la foto para darle la vuelta"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Toca para eliminar los ojos rojos"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Arrastra la foto para girarla"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Arrastra la foto para enderezarla"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-fa/strings.xml b/samples/PhotoEditor/res/values-fa/strings.xml new file mode 100644 index 0000000..b1ce3f2 --- /dev/null +++ b/samples/PhotoEditor/res/values-fa/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"بارگیری عکس برای ویرایش ممکن نیست"</string> + <string name="saving_failure" msgid="3116717307036082369">"هنگام ذخیره کردن خطایی رخ داد"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> ذخیره شد"</string> + <string name="save_photo" msgid="3125109368779997862">"عکس ویرایش شده ذخیره شود؟"</string> + <string name="yes" msgid="5402582493291792293">"بله"</string> + <string name="no" msgid="5595408018304861875">"خیر"</string> + <string name="cancel" msgid="6286688759430767307">"لغو"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"ویرایش شده"</string> + <string name="artistic_group" msgid="573091775825402562">"هنرمندانه"</string> + <string name="color_group" msgid="3390757893475444688">"رنگ"</string> + <string name="exposure_group" msgid="7019148007708100078">"نوردهی"</string> + <string name="fix_group" msgid="971450155810247383">"ثابت"</string> + <string name="autofix" msgid="1223859191856172755">"احساس خوشبختی"</string> + <string name="crossprocess" msgid="4173724489001742342">"فرآیند همگذاری"</string> + <string name="documentary" msgid="50396326708699797">"مستند"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"دو تن رنگ"</string> + <string name="filllight" msgid="2644989991700022526">"پر کردن نور"</string> + <string name="fisheye" msgid="6037488646928998921">"فیش آی"</string> + <string name="flip" msgid="2357692401826287480">"برعکس کردن"</string> + <string name="grain" msgid="7487585304579789098">"بافت فیلم"</string> + <string name="grayscale" msgid="615169770671286699">"طیف خاکستری"</string> + <string name="highlight" msgid="3902653944386623972">"قسمت های برجسته"</string> + <string name="lomoish" msgid="7793824845892532976">"شبیه Lomo"</string> + <string name="negative" msgid="1985508917342811252">"نگاتیو"</string> + <string name="posterize" msgid="4139212359561383385">"پوستری کردن"</string> + <string name="redeye" msgid="4958448806369928239">"قرمزی چشم"</string> + <string name="rotate" msgid="6607597269792373083">"چرخش"</string> + <string name="saturation" msgid="8621322012271169931">"اشباع"</string> + <string name="sepia" msgid="7978093531824705601">"سپیا"</string> + <string name="shadow" msgid="8235188588101973090">"سایه ها"</string> + <string name="sharpen" msgid="8449662378104403230">"وضوح"</string> + <string name="softfocus" msgid="6334228862566408303">"فوکوس نرم"</string> + <string name="straighten" msgid="5217801513491493491">"صاف کردن"</string> + <string name="temperature" msgid="3589958696423284897">"دما"</string> + <string name="tint" msgid="154435943863418434">"ته رنگ"</string> + <string name="vignette" msgid="7648125924662648282">"وینت"</string> + <string name="warmify" msgid="2404474974251014984">"گرم کردن"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"برای doodle کردن روی عکس رسم کنید"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"برای وارونه کردن عکس آن را بکشید"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"برای حذف قرمزی چشم ضربه بزنید"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"برای چرخاندن عکس آن را بکشید"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"برای صاف کردن عکس آن را بکشید"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-fi/strings.xml b/samples/PhotoEditor/res/values-fi/strings.xml new file mode 100644 index 0000000..4afa2d8 --- /dev/null +++ b/samples/PhotoEditor/res/values-fi/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Kuvaa ei voi ladata muokattavaksi"</string> + <string name="saving_failure" msgid="3116717307036082369">"Ongelma tallennuksessa"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> tallennettu"</string> + <string name="save_photo" msgid="3125109368779997862">"Tallenna muokattu valokuva?"</string> + <string name="yes" msgid="5402582493291792293">"Kyllä"</string> + <string name="no" msgid="5595408018304861875">"Ei"</string> + <string name="cancel" msgid="6286688759430767307">"Peruuta"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Muokattu"</string> + <string name="artistic_group" msgid="573091775825402562">"Taiteellinen"</string> + <string name="color_group" msgid="3390757893475444688">"Väri"</string> + <string name="exposure_group" msgid="7019148007708100078">"Valotus"</string> + <string name="fix_group" msgid="971450155810247383">"Korjaus"</string> + <string name="autofix" msgid="1223859191856172755">"Kokeilen onneani"</string> + <string name="crossprocess" msgid="4173724489001742342">"Ristiinkäsittely"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentti"</string> + <string name="doodle" msgid="1686409894518940990">"Piirtely"</string> + <string name="duotone" msgid="8145893940788467106">"Kaksoissävy"</string> + <string name="filllight" msgid="2644989991700022526">"Täytä vaaleat kohdat"</string> + <string name="fisheye" msgid="6037488646928998921">"Kalansilmä"</string> + <string name="flip" msgid="2357692401826287480">"Käännä"</string> + <string name="grain" msgid="7487585304579789098">"Filmin rakeisuus"</string> + <string name="grayscale" msgid="615169770671286699">"Harmaasävy"</string> + <string name="highlight" msgid="3902653944386623972">"Kohokohdat"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomomainen"</string> + <string name="negative" msgid="1985508917342811252">"Negatiivinen"</string> + <string name="posterize" msgid="4139212359561383385">"Posterisaatio"</string> + <string name="redeye" msgid="4958448806369928239">"Punasilmäisyys"</string> + <string name="rotate" msgid="6607597269792373083">"Kierrä"</string> + <string name="saturation" msgid="8621322012271169931">"Värikylläisyys"</string> + <string name="sepia" msgid="7978093531824705601">"Seepia"</string> + <string name="shadow" msgid="8235188588101973090">"Varjostus"</string> + <string name="sharpen" msgid="8449662378104403230">"Tarkennus"</string> + <string name="softfocus" msgid="6334228862566408303">"Pehmeäpiirto"</string> + <string name="straighten" msgid="5217801513491493491">"Suorista"</string> + <string name="temperature" msgid="3589958696423284897">"Lämpötila"</string> + <string name="tint" msgid="154435943863418434">"Sävytys"</string> + <string name="vignette" msgid="7648125924662648282">"Vinjetti"</string> + <string name="warmify" msgid="2404474974251014984">"Lämmitä sävyt"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Piirrä valokuvaan siirtämällä osoitin sen päälle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Käännä kuva vetämällä"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Poista punaiset silmät napauttamalla"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Käännä valokuvaa vetämällä"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Suorista valokuva vetämällä"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-fr/strings.xml b/samples/PhotoEditor/res/values-fr/strings.xml new file mode 100644 index 0000000..be8d971 --- /dev/null +++ b/samples/PhotoEditor/res/values-fr/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Impossible de charger la photo pour la retoucher."</string> + <string name="saving_failure" msgid="3116717307036082369">"Un problème est survenu lors de l\'enregistrement."</string> + <string name="photo_saved" msgid="5093564498138145422">"\"<xliff:g id="FILENAME">%s</xliff:g>\" enregistré"</string> + <string name="save_photo" msgid="3125109368779997862">"Enregistrer photo retouchée ?"</string> + <string name="yes" msgid="5402582493291792293">"Oui"</string> + <string name="no" msgid="5595408018304861875">"Non"</string> + <string name="cancel" msgid="6286688759430767307">"Annuler"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Modifiées"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistique"</string> + <string name="color_group" msgid="3390757893475444688">"Couleur"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposition"</string> + <string name="fix_group" msgid="971450155810247383">"Retouches"</string> + <string name="autofix" msgid="1223859191856172755">"J\'ai de la chance"</string> + <string name="crossprocess" msgid="4173724489001742342">"Traitement croisé"</string> + <string name="documentary" msgid="50396326708699797">"Documentaire"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Deux tons"</string> + <string name="filllight" msgid="2644989991700022526">"Éclairage d\'appoint"</string> + <string name="fisheye" msgid="6037488646928998921">"Objectif fisheye"</string> + <string name="flip" msgid="2357692401826287480">"Retourner"</string> + <string name="grain" msgid="7487585304579789098">"Grain"</string> + <string name="grayscale" msgid="615169770671286699">"Nuances de gris"</string> + <string name="highlight" msgid="3902653944386623972">"Reflets"</string> + <string name="lomoish" msgid="7793824845892532976">"Effet Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Négatif"</string> + <string name="posterize" msgid="4139212359561383385">"Postérisation"</string> + <string name="redeye" msgid="4958448806369928239">"Yeux rouges"</string> + <string name="rotate" msgid="6607597269792373083">"Rotation"</string> + <string name="saturation" msgid="8621322012271169931">"Saturation"</string> + <string name="sepia" msgid="7978093531824705601">"Sépia"</string> + <string name="shadow" msgid="8235188588101973090">"Ombres"</string> + <string name="sharpen" msgid="8449662378104403230">"Netteté"</string> + <string name="softfocus" msgid="6334228862566408303">"Flou artistique"</string> + <string name="straighten" msgid="5217801513491493491">"Redresser"</string> + <string name="temperature" msgid="3589958696423284897">"Température"</string> + <string name="tint" msgid="154435943863418434">"Coloration"</string> + <string name="vignette" msgid="7648125924662648282">"Vignetage"</string> + <string name="warmify" msgid="2404474974251014984">"Couleurs chaudes"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Dessiner sur la photo pour gribouiller"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Faire glisser la photo pour la retourner"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Appuyer pour supprimer les yeux rouges"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Faire glisser la photo pour la faire pivoter"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Faire glisser la photo pour la redresser"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-hr/strings.xml b/samples/PhotoEditor/res/values-hr/strings.xml new file mode 100644 index 0000000..bfbe0ea --- /dev/null +++ b/samples/PhotoEditor/res/values-hr/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Foto studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Ne mogu učitati fotografiju za uređivanje"</string> + <string name="saving_failure" msgid="3116717307036082369">"Došlo je do problema tijekom spremanja"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> spremljena"</string> + <string name="save_photo" msgid="3125109368779997862">"Spremiti uređenu fotografiju?"</string> + <string name="yes" msgid="5402582493291792293">"Da"</string> + <string name="no" msgid="5595408018304861875">"Ne"</string> + <string name="cancel" msgid="6286688759430767307">"Odustani"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Uređeno"</string> + <string name="artistic_group" msgid="573091775825402562">"Umjetnički"</string> + <string name="color_group" msgid="3390757893475444688">"Boja"</string> + <string name="exposure_group" msgid="7019148007708100078">"Ekspozicija"</string> + <string name="fix_group" msgid="971450155810247383">"Popravi"</string> + <string name="autofix" msgid="1223859191856172755">"Sretan"</string> + <string name="crossprocess" msgid="4173724489001742342">"Pomak boja"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentarni"</string> + <string name="doodle" msgid="1686409894518940990">"Škrabotine"</string> + <string name="duotone" msgid="8145893940788467106">"Duo-ton"</string> + <string name="filllight" msgid="2644989991700022526">"Ispuni svjetlom"</string> + <string name="fisheye" msgid="6037488646928998921">"Riblje oko"</string> + <string name="flip" msgid="2357692401826287480">"Okreni"</string> + <string name="grain" msgid="7487585304579789098">"Zrnatost filma"</string> + <string name="grayscale" msgid="615169770671286699">"Nijanse sive"</string> + <string name="highlight" msgid="3902653944386623972">"Isticanja"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomografski"</string> + <string name="negative" msgid="1985508917342811252">"Negativan"</string> + <string name="posterize" msgid="4139212359561383385">"Posterizacija"</string> + <string name="redeye" msgid="4958448806369928239">"Crvene oči"</string> + <string name="rotate" msgid="6607597269792373083">"Rotiraj"</string> + <string name="saturation" msgid="8621322012271169931">"Zasićenje"</string> + <string name="sepia" msgid="7978093531824705601">"Sepija"</string> + <string name="shadow" msgid="8235188588101973090">"Sjenčanje"</string> + <string name="sharpen" msgid="8449662378104403230">"Izoštri"</string> + <string name="softfocus" msgid="6334228862566408303">"Mekani fokus"</string> + <string name="straighten" msgid="5217801513491493491">"Poravnaj"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Svjetlija nijansa"</string> + <string name="vignette" msgid="7648125924662648282">"Vinjeta"</string> + <string name="warmify" msgid="2404474974251014984">"Stavi topliju nijansu"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Crtanje na fotografiju za doodle logotip"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Povucite sliku da biste je preokrenuli"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Dotaknite za uklanjanje crvenih očiju"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Povucite fotografiju da biste je rotirali"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Povucite fotografiju da biste je izravnali"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-hu/strings.xml b/samples/PhotoEditor/res/values-hu/strings.xml new file mode 100644 index 0000000..3dfc431 --- /dev/null +++ b/samples/PhotoEditor/res/values-hu/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"A fotó nem tölthető be szerkesztésre"</string> + <string name="saving_failure" msgid="3116717307036082369">"Hiba történt mentés közben"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> mentve"</string> + <string name="save_photo" msgid="3125109368779997862">"A szerkesztett kép mentése?"</string> + <string name="yes" msgid="5402582493291792293">"Igen"</string> + <string name="no" msgid="5595408018304861875">"Nem"</string> + <string name="cancel" msgid="6286688759430767307">"Mégse"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Szerkesztve"</string> + <string name="artistic_group" msgid="573091775825402562">"Művészi"</string> + <string name="color_group" msgid="3390757893475444688">"Szín"</string> + <string name="exposure_group" msgid="7019148007708100078">"Expozíció"</string> + <string name="fix_group" msgid="971450155810247383">"Javítás"</string> + <string name="autofix" msgid="1223859191856172755">"Jó napom van"</string> + <string name="crossprocess" msgid="4173724489001742342">"Áttűnés"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentumfilm"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Kéttónusú"</string> + <string name="filllight" msgid="2644989991700022526">"Háttérfény"</string> + <string name="fisheye" msgid="6037488646928998921">"Halszem"</string> + <string name="flip" msgid="2357692401826287480">"Tükrözés"</string> + <string name="grain" msgid="7487585304579789098">"Filmszemcse"</string> + <string name="grayscale" msgid="615169770671286699">"Szürkeárnyalat"</string> + <string name="highlight" msgid="3902653944386623972">"Kiemelt részek"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo-hatás"</string> + <string name="negative" msgid="1985508917342811252">"Negatív"</string> + <string name="posterize" msgid="4139212359561383385">"Poszterizálás"</string> + <string name="redeye" msgid="4958448806369928239">"Vörösszem"</string> + <string name="rotate" msgid="6607597269792373083">"Forgatás"</string> + <string name="saturation" msgid="8621322012271169931">"Telítettség"</string> + <string name="sepia" msgid="7978093531824705601">"Szépia"</string> + <string name="shadow" msgid="8235188588101973090">"Árnyékok"</string> + <string name="sharpen" msgid="8449662378104403230">"Élesítés"</string> + <string name="softfocus" msgid="6334228862566408303">"Lágy fókusz"</string> + <string name="straighten" msgid="5217801513491493491">"Kiegyenesítés"</string> + <string name="temperature" msgid="3589958696423284897">"Hőmérséklet"</string> + <string name="tint" msgid="154435943863418434">"Árnyalás"</string> + <string name="vignette" msgid="7648125924662648282">"Vignetta"</string> + <string name="warmify" msgid="2404474974251014984">"Melegítés"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Rajzoljon a fotóra embléma létrehozásához"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Húzza a fotót annak tükrözéséhez"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Érintse meg a vörös szem hatás eltávolításához"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Húzza a fényképet annak forgatásához"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Húzza a fényképet annak kiegyenesítéséhez"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-in/strings.xml b/samples/PhotoEditor/res/values-in/strings.xml new file mode 100644 index 0000000..7f3345c --- /dev/null +++ b/samples/PhotoEditor/res/values-in/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Tidak dapat memuat foto untuk diedit"</string> + <string name="saving_failure" msgid="3116717307036082369">"Terjadi masalah saat menyimpan"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> tersimpan"</string> + <string name="save_photo" msgid="3125109368779997862">"Simpan foto yang diedit?"</string> + <string name="yes" msgid="5402582493291792293">"Ya"</string> + <string name="no" msgid="5595408018304861875">"Tidak"</string> + <string name="cancel" msgid="6286688759430767307">"Batal"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Hasil edit"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistik"</string> + <string name="color_group" msgid="3390757893475444688">"Warna"</string> + <string name="exposure_group" msgid="7019148007708100078">"Pencahayaan"</string> + <string name="fix_group" msgid="971450155810247383">"Diperbaiki"</string> + <string name="autofix" msgid="1223859191856172755">"Lagi Beruntung"</string> + <string name="crossprocess" msgid="4173724489001742342">"Proses silang"</string> + <string name="documentary" msgid="50396326708699797">"Dokumenter"</string> + <string name="doodle" msgid="1686409894518940990">"Orat-oret"</string> + <string name="duotone" msgid="8145893940788467106">"Duo-warna"</string> + <string name="filllight" msgid="2644989991700022526">"Isi Cahaya"</string> + <string name="fisheye" msgid="6037488646928998921">"Mata Ikan"</string> + <string name="flip" msgid="2357692401826287480">"Balik"</string> + <string name="grain" msgid="7487585304579789098">"Butiran Film"</string> + <string name="grayscale" msgid="615169770671286699">"Gradasi kelabu"</string> + <string name="highlight" msgid="3902653944386623972">"Sorotan"</string> + <string name="lomoish" msgid="7793824845892532976">"Gaya Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negatif"</string> + <string name="posterize" msgid="4139212359561383385">"Posterisasi"</string> + <string name="redeye" msgid="4958448806369928239">"Mata Merah"</string> + <string name="rotate" msgid="6607597269792373083">"Putar"</string> + <string name="saturation" msgid="8621322012271169931">"Saturasi"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Bayangan"</string> + <string name="sharpen" msgid="8449662378104403230">"Pertajam"</string> + <string name="softfocus" msgid="6334228862566408303">"Fokus Lembut"</string> + <string name="straighten" msgid="5217801513491493491">"Luruskan"</string> + <string name="temperature" msgid="3589958696423284897">"Suhu"</string> + <string name="tint" msgid="154435943863418434">"Warna"</string> + <string name="vignette" msgid="7648125924662648282">"Vinyet"</string> + <string name="warmify" msgid="2404474974251014984">"Perhangat"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Menggambar pada foto untuk membuat orat-oret"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Seret foto untuk membaliknya"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Ketuk untuk menghapus mata merah"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Seret foto untuk memutarnya"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Seret foto untuk meluruskannya"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-it/strings.xml b/samples/PhotoEditor/res/values-it/strings.xml new file mode 100644 index 0000000..e60d281 --- /dev/null +++ b/samples/PhotoEditor/res/values-it/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Impossibile caricare la foto da modificare"</string> + <string name="saving_failure" msgid="3116717307036082369">"Si è verificato un problema durante il salvataggio"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> salvato"</string> + <string name="save_photo" msgid="3125109368779997862">"Salvare la foto modificata?"</string> + <string name="yes" msgid="5402582493291792293">"Sì"</string> + <string name="no" msgid="5595408018304861875">"No"</string> + <string name="cancel" msgid="6286688759430767307">"Annulla"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Modificata"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistici"</string> + <string name="color_group" msgid="3390757893475444688">"Colore"</string> + <string name="exposure_group" msgid="7019148007708100078">"Esposizione"</string> + <string name="fix_group" msgid="971450155810247383">"Correggi"</string> + <string name="autofix" msgid="1223859191856172755">"Mi sento fortunato"</string> + <string name="crossprocess" msgid="4173724489001742342">"Cross process"</string> + <string name="documentary" msgid="50396326708699797">"Documentario"</string> + <string name="doodle" msgid="1686409894518940990">"Scarabocchio"</string> + <string name="duotone" msgid="8145893940788467106">"Bitonale"</string> + <string name="filllight" msgid="2644989991700022526">"Luce di riempimento"</string> + <string name="fisheye" msgid="6037488646928998921">"Fisheye"</string> + <string name="flip" msgid="2357692401826287480">"Capovolgi"</string> + <string name="grain" msgid="7487585304579789098">"Grana pellicola"</string> + <string name="grayscale" msgid="615169770671286699">"Scala di grigi"</string> + <string name="highlight" msgid="3902653944386623972">"Luci"</string> + <string name="lomoish" msgid="7793824845892532976">"Effetto Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negativo"</string> + <string name="posterize" msgid="4139212359561383385">"Posterizza"</string> + <string name="redeye" msgid="4958448806369928239">"Occhi rossi"</string> + <string name="rotate" msgid="6607597269792373083">"Ruota"</string> + <string name="saturation" msgid="8621322012271169931">"Saturazione"</string> + <string name="sepia" msgid="7978093531824705601">"Seppia"</string> + <string name="shadow" msgid="8235188588101973090">"Ombre"</string> + <string name="sharpen" msgid="8449662378104403230">"Nitidezza"</string> + <string name="softfocus" msgid="6334228862566408303">"Sfocatura diffusa"</string> + <string name="straighten" msgid="5217801513491493491">"Raddrizza"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Tinta"</string> + <string name="vignette" msgid="7648125924662648282">"Vignetta"</string> + <string name="warmify" msgid="2404474974251014984">"Colori caldi"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Disegna sulla foto per scarabocchiarla"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Trascina la foto per girarla"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Tocca per rimuovere gli occhi rossi"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Trascina la foto per ruotarla"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Trascina la foto per raddrizzarla"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-iw/strings.xml b/samples/PhotoEditor/res/values-iw/strings.xml new file mode 100644 index 0000000..ea6a0fe --- /dev/null +++ b/samples/PhotoEditor/res/values-iw/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"לא ניתן לטעון את התמונה לעריכה"</string> + <string name="saving_failure" msgid="3116717307036082369">"אירעה בעיה במהלך השמירה"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> נשמר"</string> + <string name="save_photo" msgid="3125109368779997862">"לשמור את התמונה הערוכה?"</string> + <string name="yes" msgid="5402582493291792293">"כן"</string> + <string name="no" msgid="5595408018304861875">"לא"</string> + <string name="cancel" msgid="6286688759430767307">"ביטול"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"תמונות ערוכות"</string> + <string name="artistic_group" msgid="573091775825402562">"אמנותי"</string> + <string name="color_group" msgid="3390757893475444688">"צבע"</string> + <string name="exposure_group" msgid="7019148007708100078">"חשיפה"</string> + <string name="fix_group" msgid="971450155810247383">"תיקונים"</string> + <string name="autofix" msgid="1223859191856172755">"יותר מזל משכל"</string> + <string name="crossprocess" msgid="4173724489001742342">"פיתוח מוצלב"</string> + <string name="documentary" msgid="50396326708699797">"דוקומנטרי"</string> + <string name="doodle" msgid="1686409894518940990">"ציור"</string> + <string name="duotone" msgid="8145893940788467106">"שני גוונים"</string> + <string name="filllight" msgid="2644989991700022526">"אור מילוי"</string> + <string name="fisheye" msgid="6037488646928998921">"עדשת עין הדג"</string> + <string name="flip" msgid="2357692401826287480">"הפוך"</string> + <string name="grain" msgid="7487585304579789098">"גרעיניות סרט"</string> + <string name="grayscale" msgid="615169770671286699">"גווני אפור"</string> + <string name="highlight" msgid="3902653944386623972">"הבהרה"</string> + <string name="lomoish" msgid="7793824845892532976">"בסגנון Lomo"</string> + <string name="negative" msgid="1985508917342811252">"נגטיב"</string> + <string name="posterize" msgid="4139212359561383385">"מצב פוסטר (Posterize)"</string> + <string name="redeye" msgid="4958448806369928239">"עין אדומה"</string> + <string name="rotate" msgid="6607597269792373083">"סיבוב"</string> + <string name="saturation" msgid="8621322012271169931">"רוויה"</string> + <string name="sepia" msgid="7978093531824705601">"חום-ספיה"</string> + <string name="shadow" msgid="8235188588101973090">"צלליות"</string> + <string name="sharpen" msgid="8449662378104403230">"שפר חדות"</string> + <string name="softfocus" msgid="6334228862566408303">"מיקוד רך"</string> + <string name="straighten" msgid="5217801513491493491">"יישר"</string> + <string name="temperature" msgid="3589958696423284897">"טמפרטורה"</string> + <string name="tint" msgid="154435943863418434">"גוון"</string> + <string name="vignette" msgid="7648125924662648282">"שוליים דהויים"</string> + <string name="warmify" msgid="2404474974251014984">"הפוך לחמים יותר"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"גרור על גבי התמונה כדי לצייר עליה"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"גרור את התמונה כדי להפוך אותה"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"הקש כדי להסיר עיניים אדומות"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"גרור את התמונה כדי לסובב אותה"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"גרור את התמונה כדי ליישר אותה"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-ja/strings.xml b/samples/PhotoEditor/res/values-ja/strings.xml new file mode 100644 index 0000000..fcf47cc --- /dev/null +++ b/samples/PhotoEditor/res/values-ja/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"フォトスタジオ"</string> + <string name="loading_failure" msgid="8575831322115054185">"写真を編集用に読み込むことができません。"</string> + <string name="saving_failure" msgid="3116717307036082369">"保存中に問題が発生しました"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g>を保存しました"</string> + <string name="save_photo" msgid="3125109368779997862">"編集した写真を保存しますか?"</string> + <string name="yes" msgid="5402582493291792293">"はい"</string> + <string name="no" msgid="5595408018304861875">"いいえ"</string> + <string name="cancel" msgid="6286688759430767307">"キャンセル"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"編集済み"</string> + <string name="artistic_group" msgid="573091775825402562">"芸術的"</string> + <string name="color_group" msgid="3390757893475444688">"色"</string> + <string name="exposure_group" msgid="7019148007708100078">"露出"</string> + <string name="fix_group" msgid="971450155810247383">"修正"</string> + <string name="autofix" msgid="1223859191856172755">"ラッキー"</string> + <string name="crossprocess" msgid="4173724489001742342">"クロスプロセス"</string> + <string name="documentary" msgid="50396326708699797">"ドキュメンタリー"</string> + <string name="doodle" msgid="1686409894518940990">"落書き"</string> + <string name="duotone" msgid="8145893940788467106">"デュオトーン"</string> + <string name="filllight" msgid="2644989991700022526">"明るさ調整"</string> + <string name="fisheye" msgid="6037488646928998921">"魚眼レンズ"</string> + <string name="flip" msgid="2357692401826287480">"反転"</string> + <string name="grain" msgid="7487585304579789098">"フィルムグレイン"</string> + <string name="grayscale" msgid="615169770671286699">"グレースケール"</string> + <string name="highlight" msgid="3902653944386623972">"ハイライト"</string> + <string name="lomoish" msgid="7793824845892532976">"LOMO風"</string> + <string name="negative" msgid="1985508917342811252">"白黒反転"</string> + <string name="posterize" msgid="4139212359561383385">"ポスタライズ"</string> + <string name="redeye" msgid="4958448806369928239">"赤目処理"</string> + <string name="rotate" msgid="6607597269792373083">"回転"</string> + <string name="saturation" msgid="8621322012271169931">"彩度"</string> + <string name="sepia" msgid="7978093531824705601">"セピア"</string> + <string name="shadow" msgid="8235188588101973090">"シャドウ"</string> + <string name="sharpen" msgid="8449662378104403230">"シャープ"</string> + <string name="softfocus" msgid="6334228862566408303">"ソフトフォーカス"</string> + <string name="straighten" msgid="5217801513491493491">"傾き調整"</string> + <string name="temperature" msgid="3589958696423284897">"温度"</string> + <string name="tint" msgid="154435943863418434">"色合い"</string> + <string name="vignette" msgid="7648125924662648282">"周辺減光"</string> + <string name="warmify" msgid="2404474974251014984">"ウォーム"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"画像の上に書き込みます"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"画像をめくるにはドラッグします"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"赤目を補正するにはタップします"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"画像を回転させるにはドラッグします"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"画像をまっすぐにするにはドラッグします"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-ko/strings.xml b/samples/PhotoEditor/res/values-ko/strings.xml new file mode 100644 index 0000000..2eaa100 --- /dev/null +++ b/samples/PhotoEditor/res/values-ko/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"수정할 사진을 로드할 수 없습니다."</string> + <string name="saving_failure" msgid="3116717307036082369">"저장하는 동안 문제가 발생했습니다."</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g>이(가) 저장되었습니다."</string> + <string name="save_photo" msgid="3125109368779997862">"수정한 사진을 저장하시겠습니까?"</string> + <string name="yes" msgid="5402582493291792293">"예"</string> + <string name="no" msgid="5595408018304861875">"아니요"</string> + <string name="cancel" msgid="6286688759430767307">"취소"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"수정된 사진"</string> + <string name="artistic_group" msgid="573091775825402562">"예술적"</string> + <string name="color_group" msgid="3390757893475444688">"색상"</string> + <string name="exposure_group" msgid="7019148007708100078">"노출"</string> + <string name="fix_group" msgid="971450155810247383">"조절"</string> + <string name="autofix" msgid="1223859191856172755">"Feel Lucky"</string> + <string name="crossprocess" msgid="4173724489001742342">"크로스 프로세스"</string> + <string name="documentary" msgid="50396326708699797">"다큐멘터리"</string> + <string name="doodle" msgid="1686409894518940990">"낙서"</string> + <string name="duotone" msgid="8145893940788467106">"더블톤"</string> + <string name="filllight" msgid="2644989991700022526">"밝게"</string> + <string name="fisheye" msgid="6037488646928998921">"어안렌즈"</string> + <string name="flip" msgid="2357692401826287480">"방향 바꾸기"</string> + <string name="grain" msgid="7487585304579789098">"거친 필름"</string> + <string name="grayscale" msgid="615169770671286699">"그레이 스케일"</string> + <string name="highlight" msgid="3902653944386623972">"하이라이트"</string> + <string name="lomoish" msgid="7793824845892532976">"로모 스타일"</string> + <string name="negative" msgid="1985508917342811252">"네거티브"</string> + <string name="posterize" msgid="4139212359561383385">"포스터"</string> + <string name="redeye" msgid="4958448806369928239">"적목현상"</string> + <string name="rotate" msgid="6607597269792373083">"회전"</string> + <string name="saturation" msgid="8621322012271169931">"채도"</string> + <string name="sepia" msgid="7978093531824705601">"세피아"</string> + <string name="shadow" msgid="8235188588101973090">"그림자"</string> + <string name="sharpen" msgid="8449662378104403230">"선명하게"</string> + <string name="softfocus" msgid="6334228862566408303">"소프트 포커스"</string> + <string name="straighten" msgid="5217801513491493491">"똑바르게"</string> + <string name="temperature" msgid="3589958696423284897">"색온도"</string> + <string name="tint" msgid="154435943863418434">"농담"</string> + <string name="vignette" msgid="7648125924662648282">"비네트"</string> + <string name="warmify" msgid="2404474974251014984">"따뜻하게"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"사진에 그림을 그려 낙서하기"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"사진을 드래그하여 방향 바꾸기"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"터치하여 적목 현상 제거"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"드래그하여 사진 회전"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"사진을 드래그하여 반듯하게 하기"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-lt/strings.xml b/samples/PhotoEditor/res/values-lt/strings.xml new file mode 100644 index 0000000..f49fe84 --- /dev/null +++ b/samples/PhotoEditor/res/values-lt/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Neįmanoma įkelti nuotr., kad ją būtų g. redaguoti."</string> + <string name="saving_failure" msgid="3116717307036082369">"Išsaugant iškilo problema"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> išsaugota"</string> + <string name="save_photo" msgid="3125109368779997862">"Išsaugoti redaguotą nuotrauką?"</string> + <string name="yes" msgid="5402582493291792293">"Taip"</string> + <string name="no" msgid="5595408018304861875">"Ne"</string> + <string name="cancel" msgid="6286688759430767307">"Atšaukti"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Redaguota"</string> + <string name="artistic_group" msgid="573091775825402562">"Meniška"</string> + <string name="color_group" msgid="3390757893475444688">"Spalva"</string> + <string name="exposure_group" msgid="7019148007708100078">"Išlaikymas"</string> + <string name="fix_group" msgid="971450155810247383">"Pataisyti"</string> + <string name="autofix" msgid="1223859191856172755">"Man sekasi"</string> + <string name="crossprocess" msgid="4173724489001742342">"Kryžm. apdor."</string> + <string name="documentary" msgid="50396326708699797">"Dokumentika"</string> + <string name="doodle" msgid="1686409894518940990">"Logotipų puoš."</string> + <string name="duotone" msgid="8145893940788467106">"Du tonai"</string> + <string name="filllight" msgid="2644989991700022526">"Užpild. šviesa"</string> + <string name="fisheye" msgid="6037488646928998921">"Žuvies akis"</string> + <string name="flip" msgid="2357692401826287480">"Apversti"</string> + <string name="grain" msgid="7487585304579789098">"Juostos grūd."</string> + <string name="grayscale" msgid="615169770671286699">"Pilkumo tonas"</string> + <string name="highlight" msgid="3902653944386623972">"Paryškinimai"</string> + <string name="lomoish" msgid="7793824845892532976">"„Lomo“ tipo"</string> + <string name="negative" msgid="1985508917342811252">"Negatyvas"</string> + <string name="posterize" msgid="4139212359561383385">"Mažinti spalv."</string> + <string name="redeye" msgid="4958448806369928239">"Raudonos akys"</string> + <string name="rotate" msgid="6607597269792373083">"Pasukti"</string> + <string name="saturation" msgid="8621322012271169931">"Spalvų sodr."</string> + <string name="sepia" msgid="7978093531824705601">"Tamsiai rusv."</string> + <string name="shadow" msgid="8235188588101973090">"Šešėliai"</string> + <string name="sharpen" msgid="8449662378104403230">"Paryškinti"</string> + <string name="softfocus" msgid="6334228862566408303">"Švelnus fokus."</string> + <string name="straighten" msgid="5217801513491493491">"Tiesinti"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatūra"</string> + <string name="tint" msgid="154435943863418434">"Atspalvis"</string> + <string name="vignette" msgid="7648125924662648282">"Vinjetė"</string> + <string name="warmify" msgid="2404474974251014984">"Naud. šilt. sp."</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Pieškite ant nuotraukos, jei norite taikyti logotipų puošybą"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Vilkite nuotrauką, kad ją apverstumėte"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Palieskite, kad pašalintumėte raudonas akis"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Vilkite nuotrauką, kad ją apsuktumėte"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Vilkite nuotrauką, kad ją ištiesintumėte"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-lv/strings.xml b/samples/PhotoEditor/res/values-lv/strings.xml new file mode 100644 index 0000000..465d12b --- /dev/null +++ b/samples/PhotoEditor/res/values-lv/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Fotostudija"</string> + <string name="loading_failure" msgid="8575831322115054185">"Nevar ielādēt fotoattēlu, lai to rediģētu."</string> + <string name="saving_failure" msgid="3116717307036082369">"Saglabāšanas laikā radās problēma."</string> + <string name="photo_saved" msgid="5093564498138145422">"Fails <xliff:g id="FILENAME">%s</xliff:g> ir saglabāts."</string> + <string name="save_photo" msgid="3125109368779997862">"Vai saglabāt rediģēto fotoattēlu?"</string> + <string name="yes" msgid="5402582493291792293">"Jā"</string> + <string name="no" msgid="5595408018304861875">"Nē"</string> + <string name="cancel" msgid="6286688759430767307">"Atcelt"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Rediģēti"</string> + <string name="artistic_group" msgid="573091775825402562">"Māksla"</string> + <string name="color_group" msgid="3390757893475444688">"Krāsa"</string> + <string name="exposure_group" msgid="7019148007708100078">"Ekspozīcija"</string> + <string name="fix_group" msgid="971450155810247383">"Labot"</string> + <string name="autofix" msgid="1223859191856172755">"Ticu veiksmei"</string> + <string name="crossprocess" msgid="4173724489001742342">"Kļūd. apstrāde"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentārs"</string> + <string name="doodle" msgid="1686409894518940990">"Kricelējums"</string> + <string name="duotone" msgid="8145893940788467106">"Divtoņu"</string> + <string name="filllight" msgid="2644989991700022526">"Izm. pretgaismu"</string> + <string name="fisheye" msgid="6037488646928998921">"Platleņķis"</string> + <string name="flip" msgid="2357692401826287480">"Apvērst"</string> + <string name="grain" msgid="7487585304579789098">"Graudaina filma"</string> + <string name="grayscale" msgid="615169770671286699">"Pelēktoņu"</string> + <string name="highlight" msgid="3902653944386623972">"Gaismas efekti"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomogrāfija"</string> + <string name="negative" msgid="1985508917342811252">"Negatīvs"</string> + <string name="posterize" msgid="4139212359561383385">"Veidot plakātu"</string> + <string name="redeye" msgid="4958448806369928239">"Sarkanās acis"</string> + <string name="rotate" msgid="6607597269792373083">"Pagriezt"</string> + <string name="saturation" msgid="8621322012271169931">"Piesātinājums"</string> + <string name="sepia" msgid="7978093531824705601">"Sēpija"</string> + <string name="shadow" msgid="8235188588101973090">"Ēnas"</string> + <string name="sharpen" msgid="8449662378104403230">"Padarīt asāku"</string> + <string name="softfocus" msgid="6334228862566408303">"Neass attēls"</string> + <string name="straighten" msgid="5217801513491493491">"Iztaisnot"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatūra"</string> + <string name="tint" msgid="154435943863418434">"Nianse"</string> + <string name="vignette" msgid="7648125924662648282">"Vinjete"</string> + <string name="warmify" msgid="2404474974251014984">"Siltināt"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Velciet uz fotoattēla, lai kricelētu."</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Velciet fotoattēlu, lai to apgrieztu."</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Pieskarieties, lai noņemtu sarkano acu efektu."</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Velciet fotoattēlu, lai to pagrieztu."</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Velciet fotoattēlu, lai to iztaisnotu."</string> +</resources> diff --git a/samples/PhotoEditor/res/values-ms/strings.xml b/samples/PhotoEditor/res/values-ms/strings.xml new file mode 100644 index 0000000..f6c2e62 --- /dev/null +++ b/samples/PhotoEditor/res/values-ms/strings.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Tidak boleh memuatkan foto untuk pengeditan"</string> + <string name="saving_failure" msgid="3116717307036082369">"Ralat berlaku semasa menyimpan"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> disimpan"</string> + <string name="save_photo" msgid="3125109368779997862">"Simpan foto yang diedit?"</string> + <string name="yes" msgid="5402582493291792293">"Ya"</string> + <string name="no" msgid="5595408018304861875">"Tidak"</string> + <string name="cancel" msgid="6286688759430767307">"Batal"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Diedit"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistik"</string> + <string name="color_group" msgid="3390757893475444688">"Warna"</string> + <string name="exposure_group" msgid="7019148007708100078">"Dedahan"</string> + <string name="fix_group" msgid="971450155810247383">"Baiki"</string> + <string name="autofix" msgid="1223859191856172755">"Rasa Bertuah"</string> + <string name="crossprocess" msgid="4173724489001742342">"Proses silang"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentari"</string> + <string name="doodle" msgid="1686409894518940990">"Coretan"</string> + <string name="duotone" msgid="8145893940788467106">"Dua tona"</string> + <string name="filllight" msgid="2644989991700022526">"Cahaya Pemenuh"</string> + <string name="fisheye" msgid="6037488646928998921">"Mata ikan"</string> + <string name="flip" msgid="2357692401826287480">"Balikkan"</string> + <string name="grain" msgid="7487585304579789098">"Ira Filem"</string> + <string name="grayscale" msgid="615169770671286699">"Skala kelabu"</string> + <string name="highlight" msgid="3902653944386623972">"Serlahan"</string> + <string name="lomoish" msgid="7793824845892532976">"Seperti Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negatif"</string> + <string name="posterize" msgid="4139212359561383385">"Pemposteran"</string> + <string name="redeye" msgid="4958448806369928239">"Mata Merah"</string> + <string name="rotate" msgid="6607597269792373083">"Putar"</string> + <string name="saturation" msgid="8621322012271169931">"Ketepuan"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Bayang-bayang"</string> + <string name="sharpen" msgid="8449662378104403230">"Tajamkan"</string> + <string name="softfocus" msgid="6334228862566408303">"Fokus Lembut"</string> + <string name="straighten" msgid="5217801513491493491">"Luruskan"</string> + <string name="temperature" msgid="3589958696423284897">"Suhu"</string> + <string name="tint" msgid="154435943863418434">"Seri warna"</string> + <string name="vignette" msgid="7648125924662648282">"Vignet"</string> + <string name="warmify" msgid="2404474974251014984">"Hangatkan"</string> + <!-- no translation found for doodle_tooltip (2902117272374362915) --> + <skip /> + <!-- no translation found for flip_tooltip (2700943256714731737) --> + <skip /> + <!-- no translation found for redeye_tooltip (9112774042113471358) --> + <skip /> + <!-- no translation found for rotate_tooltip (7008602969130734229) --> + <skip /> + <!-- no translation found for straighten_tooltip (4846317027139212339) --> + <skip /> +</resources> diff --git a/samples/PhotoEditor/res/values-nb/strings.xml b/samples/PhotoEditor/res/values-nb/strings.xml new file mode 100644 index 0000000..b36ca86 --- /dev/null +++ b/samples/PhotoEditor/res/values-nb/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Kan ikke laste inn bildet for redigering"</string> + <string name="saving_failure" msgid="3116717307036082369">"Det oppstod et problem under lagring"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> er lagret"</string> + <string name="save_photo" msgid="3125109368779997862">"Vil du lagre det redigerte bildet?"</string> + <string name="yes" msgid="5402582493291792293">"Ja"</string> + <string name="no" msgid="5595408018304861875">"Nei"</string> + <string name="cancel" msgid="6286688759430767307">"Avbryt"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Redigert"</string> + <string name="artistic_group" msgid="573091775825402562">"Kunstnerisk"</string> + <string name="color_group" msgid="3390757893475444688">"Farge"</string> + <string name="exposure_group" msgid="7019148007708100078">"Eksponering"</string> + <string name="fix_group" msgid="971450155810247383">"Fiks"</string> + <string name="autofix" msgid="1223859191856172755">"Ta sjansen"</string> + <string name="crossprocess" msgid="4173724489001742342">"Kryssfremkall."</string> + <string name="documentary" msgid="50396326708699797">"Dokumentar"</string> + <string name="doodle" msgid="1686409894518940990">"Drodle"</string> + <string name="duotone" msgid="8145893940788467106">"Tofargebilde"</string> + <string name="filllight" msgid="2644989991700022526">"Utfyllingslys"</string> + <string name="fisheye" msgid="6037488646928998921">"Fiskeøye"</string> + <string name="flip" msgid="2357692401826287480">"Vend"</string> + <string name="grain" msgid="7487585304579789098">"Kornete oppløs."</string> + <string name="grayscale" msgid="615169770671286699">"Gråtoner"</string> + <string name="highlight" msgid="3902653944386623972">"Gjør lysere"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo-aktig"</string> + <string name="negative" msgid="1985508917342811252">"Negativt"</string> + <string name="posterize" msgid="4139212359561383385">"Plakateffekt"</string> + <string name="redeye" msgid="4958448806369928239">"Røde øyne"</string> + <string name="rotate" msgid="6607597269792373083">"Rotering"</string> + <string name="saturation" msgid="8621322012271169931">"Metning"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Skygger"</string> + <string name="sharpen" msgid="8449662378104403230">"Gjør skarpere"</string> + <string name="softfocus" msgid="6334228862566408303">"Kantdiffusering"</string> + <string name="straighten" msgid="5217801513491493491">"Rett opp"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatur"</string> + <string name="tint" msgid="154435943863418434">"Fargetone"</string> + <string name="vignette" msgid="7648125924662648282">"Vignettering"</string> + <string name="warmify" msgid="2404474974251014984">"Gjør varmere"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Tegn på bildet for å drodle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Dra bildet for å snu det"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Trykk for å fjerne røde øyne"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Dra bildet for å rotere det"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Dra bilde for å rette på det"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-nl/strings.xml b/samples/PhotoEditor/res/values-nl/strings.xml new file mode 100644 index 0000000..9c7e946 --- /dev/null +++ b/samples/PhotoEditor/res/values-nl/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Kan de foto niet laden om te bewerken"</string> + <string name="saving_failure" msgid="3116717307036082369">"Er is een probleem opgetreden tijdens het opslaan"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> opgeslagen"</string> + <string name="save_photo" msgid="3125109368779997862">"Bewerkte foto opslaan?"</string> + <string name="yes" msgid="5402582493291792293">"Ja"</string> + <string name="no" msgid="5595408018304861875">"Nee"</string> + <string name="cancel" msgid="6286688759430767307">"Annuleren"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Bewerkt"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistiek"</string> + <string name="color_group" msgid="3390757893475444688">"Kleur"</string> + <string name="exposure_group" msgid="7019148007708100078">"Belichting"</string> + <string name="fix_group" msgid="971450155810247383">"Verbeteren"</string> + <string name="autofix" msgid="1223859191856172755">"Ik doe een gok"</string> + <string name="crossprocess" msgid="4173724489001742342">"Kruisverwerking"</string> + <string name="documentary" msgid="50396326708699797">"Documentaire"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Duotone"</string> + <string name="filllight" msgid="2644989991700022526">"Licht invullen"</string> + <string name="fisheye" msgid="6037488646928998921">"Visooglens"</string> + <string name="flip" msgid="2357692401826287480">"Spiegelen"</string> + <string name="grain" msgid="7487585304579789098">"Korrelstructuur"</string> + <string name="grayscale" msgid="615169770671286699">"Grijstinten"</string> + <string name="highlight" msgid="3902653944386623972">"Lichter maken"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo-achtig"</string> + <string name="negative" msgid="1985508917342811252">"Negatief"</string> + <string name="posterize" msgid="4139212359561383385">"Postereffect"</string> + <string name="redeye" msgid="4958448806369928239">"Rode ogen"</string> + <string name="rotate" msgid="6607597269792373083">"Draaien"</string> + <string name="saturation" msgid="8621322012271169931">"Verzadiging"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Schaduwen"</string> + <string name="sharpen" msgid="8449662378104403230">"Scherper maken"</string> + <string name="softfocus" msgid="6334228862566408303">"Zachte focus"</string> + <string name="straighten" msgid="5217801513491493491">"Recht maken"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatuur"</string> + <string name="tint" msgid="154435943863418434">"Tint"</string> + <string name="vignette" msgid="7648125924662648282">"Vervloeiende randen"</string> + <string name="warmify" msgid="2404474974251014984">"Warmer maken"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Teken op de foto om hierop te krabbelen"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Sleep de foto om deze te spiegelen"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Tik om rode ogen te verwijderen"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Sleep de foto om deze te draaien"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Sleep de foto om deze recht te zetten"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-pl/strings.xml b/samples/PhotoEditor/res/values-pl/strings.xml new file mode 100644 index 0000000..c14104c --- /dev/null +++ b/samples/PhotoEditor/res/values-pl/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Studio fotograficzne"</string> + <string name="loading_failure" msgid="8575831322115054185">"Nie można wczytać zdjęcia do edytowania."</string> + <string name="saving_failure" msgid="3116717307036082369">"Podczas zapisu wystąpił problem."</string> + <string name="photo_saved" msgid="5093564498138145422">"Plik <xliff:g id="FILENAME">%s</xliff:g> został zapisany."</string> + <string name="save_photo" msgid="3125109368779997862">"Czy zapisać edytowane zdjęcie?"</string> + <string name="yes" msgid="5402582493291792293">"Tak"</string> + <string name="no" msgid="5595408018304861875">"Nie"</string> + <string name="cancel" msgid="6286688759430767307">"Anuluj"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Edytowane"</string> + <string name="artistic_group" msgid="573091775825402562">"Artystyczne"</string> + <string name="color_group" msgid="3390757893475444688">"Kolor"</string> + <string name="exposure_group" msgid="7019148007708100078">"Ekspozycja"</string> + <string name="fix_group" msgid="971450155810247383">"Poprawki"</string> + <string name="autofix" msgid="1223859191856172755">"Szczęśliwy traf"</string> + <string name="crossprocess" msgid="4173724489001742342">"Proces krosowy"</string> + <string name="documentary" msgid="50396326708699797">"Dokument"</string> + <string name="doodle" msgid="1686409894518940990">"Bazgroły"</string> + <string name="duotone" msgid="8145893940788467106">"Dwuton"</string> + <string name="filllight" msgid="2644989991700022526">"Doświetlenie"</string> + <string name="fisheye" msgid="6037488646928998921">"Rybie oko"</string> + <string name="flip" msgid="2357692401826287480">"Odwrócenie"</string> + <string name="grain" msgid="7487585304579789098">"Ziarno kliszy"</string> + <string name="grayscale" msgid="615169770671286699">"Skala szarości"</string> + <string name="highlight" msgid="3902653944386623972">"Podświetlenie"</string> + <string name="lomoish" msgid="7793824845892532976">"Łomografia"</string> + <string name="negative" msgid="1985508917342811252">"Negatyw"</string> + <string name="posterize" msgid="4139212359561383385">"Posteryzacja"</string> + <string name="redeye" msgid="4958448806369928239">"Czerwone oczy"</string> + <string name="rotate" msgid="6607597269792373083">"Obrót"</string> + <string name="saturation" msgid="8621322012271169931">"Nasycenie"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Cienie"</string> + <string name="sharpen" msgid="8449662378104403230">"Wyostrzenie"</string> + <string name="softfocus" msgid="6334228862566408303">"Nieostrość"</string> + <string name="straighten" msgid="5217801513491493491">"Wyprostowanie"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Odcień"</string> + <string name="vignette" msgid="7648125924662648282">"Winietowanie"</string> + <string name="warmify" msgid="2404474974251014984">"Ocieplenie"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Rysuj po zdjęciu, aby dodać bazgroły."</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Przeciągnij zdjęcie, aby je odwrócić."</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Dotknij, aby usunąć efekt czerwonych oczu."</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Przeciągnij zdjęcie, aby je obrócić."</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Przeciągnij zdjęcie, aby je wyprostować."</string> +</resources> diff --git a/samples/PhotoEditor/res/values-pt-rPT/strings.xml b/samples/PhotoEditor/res/values-pt-rPT/strings.xml new file mode 100644 index 0000000..9547595 --- /dev/null +++ b/samples/PhotoEditor/res/values-pt-rPT/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Não é possível carregar a fotografia para edição"</string> + <string name="saving_failure" msgid="3116717307036082369">"Ocorreu um problema ao guardar"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> guardado"</string> + <string name="save_photo" msgid="3125109368779997862">"Guardar a fotografia editada?"</string> + <string name="yes" msgid="5402582493291792293">"Sim"</string> + <string name="no" msgid="5595408018304861875">"Não"</string> + <string name="cancel" msgid="6286688759430767307">"Cancelar"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Editado"</string> + <string name="artistic_group" msgid="573091775825402562">"Artístico"</string> + <string name="color_group" msgid="3390757893475444688">"Cor"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposição"</string> + <string name="fix_group" msgid="971450155810247383">"Corrigir"</string> + <string name="autofix" msgid="1223859191856172755">"Sente-se com Sorte"</string> + <string name="crossprocess" msgid="4173724489001742342">"Processo cruzado"</string> + <string name="documentary" msgid="50396326708699797">"Documentário"</string> + <string name="doodle" msgid="1686409894518940990">"Rabiscar"</string> + <string name="duotone" msgid="8145893940788467106">"Dois tons"</string> + <string name="filllight" msgid="2644989991700022526">"Preench. Claro"</string> + <string name="fisheye" msgid="6037488646928998921">"Olho de peixe"</string> + <string name="flip" msgid="2357692401826287480">"Inverter"</string> + <string name="grain" msgid="7487585304579789098">"Filme Granulado"</string> + <string name="grayscale" msgid="615169770671286699">"Escala de cinzentos"</string> + <string name="highlight" msgid="3902653944386623972">"Realces"</string> + <string name="lomoish" msgid="7793824845892532976">"Pseudo Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negativo"</string> + <string name="posterize" msgid="4139212359561383385">"Póster"</string> + <string name="redeye" msgid="4958448806369928239">"Olhos Vermelhos"</string> + <string name="rotate" msgid="6607597269792373083">"Rodar"</string> + <string name="saturation" msgid="8621322012271169931">"Saturação"</string> + <string name="sepia" msgid="7978093531824705601">"Sépia"</string> + <string name="shadow" msgid="8235188588101973090">"Sombras"</string> + <string name="sharpen" msgid="8449662378104403230">"Aumentar nitidez"</string> + <string name="softfocus" msgid="6334228862566408303">"Focagem suave"</string> + <string name="straighten" msgid="5217801513491493491">"Endireitar"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Tonalidade"</string> + <string name="vignette" msgid="7648125924662648282">"Vinheta"</string> + <string name="warmify" msgid="2404474974251014984">"Tons quentes"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Desenhe na fotografia para rabiscar"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Arraste a fotografia para virá-la"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Toque para remover o efeito de olhos vermelhos"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Arraste a fotografia para rodá-la"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Arraste a fotografia para endireitá-la"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-pt/strings.xml b/samples/PhotoEditor/res/values-pt/strings.xml new file mode 100644 index 0000000..132fb68 --- /dev/null +++ b/samples/PhotoEditor/res/values-pt/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Não é possível carregar a foto para edição"</string> + <string name="saving_failure" msgid="3116717307036082369">"Ocorreu um problema durante a ação de salvar"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> salvo"</string> + <string name="save_photo" msgid="3125109368779997862">"Salvar foto editada?"</string> + <string name="yes" msgid="5402582493291792293">"Sim"</string> + <string name="no" msgid="5595408018304861875">"Não"</string> + <string name="cancel" msgid="6286688759430767307">"Cancelar"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Editado"</string> + <string name="artistic_group" msgid="573091775825402562">"Artístico"</string> + <string name="color_group" msgid="3390757893475444688">"Cor"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposição"</string> + <string name="fix_group" msgid="971450155810247383">"Fixar"</string> + <string name="autofix" msgid="1223859191856172755">"Se sente sort."</string> + <string name="crossprocess" msgid="4173724489001742342">"Proc. cruzado"</string> + <string name="documentary" msgid="50396326708699797">"Documentário"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Duotone"</string> + <string name="filllight" msgid="2644989991700022526">"Luz de preench."</string> + <string name="fisheye" msgid="6037488646928998921">"Olho de peixe"</string> + <string name="flip" msgid="2357692401826287480">"Inverter"</string> + <string name="grain" msgid="7487585304579789098">"Granulado"</string> + <string name="grayscale" msgid="615169770671286699">"Escala de cinza"</string> + <string name="highlight" msgid="3902653944386623972">"Destaques"</string> + <string name="lomoish" msgid="7793824845892532976">"Est. câm. Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negativo"</string> + <string name="posterize" msgid="4139212359561383385">"Transf. em pôster"</string> + <string name="redeye" msgid="4958448806369928239">"Olhos vermelhos"</string> + <string name="rotate" msgid="6607597269792373083">"Girar"</string> + <string name="saturation" msgid="8621322012271169931">"Saturação"</string> + <string name="sepia" msgid="7978093531824705601">"Sépia"</string> + <string name="shadow" msgid="8235188588101973090">"Sombras"</string> + <string name="sharpen" msgid="8449662378104403230">"Aument. nitidez"</string> + <string name="softfocus" msgid="6334228862566408303">"Filtro difusor"</string> + <string name="straighten" msgid="5217801513491493491">"Endireitar"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Tingir"</string> + <string name="vignette" msgid="7648125924662648282">"Vinheta"</string> + <string name="warmify" msgid="2404474974251014984">"Tons + quentes"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Desenhe na foto para rabiscar"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Arraste a foto para invertê-la"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Toque para remover olhos vermelhos"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Arraste a foto para girá-la"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Arraste a foto para endireitá-la"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-ro/strings.xml b/samples/PhotoEditor/res/values-ro/strings.xml new file mode 100644 index 0000000..997e41c --- /dev/null +++ b/samples/PhotoEditor/res/values-ro/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Studio foto"</string> + <string name="loading_failure" msgid="8575831322115054185">"Nu se poate încărca fotografia pentru editare"</string> + <string name="saving_failure" msgid="3116717307036082369">"A apărut o problemă la salvare"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> salvate"</string> + <string name="save_photo" msgid="3125109368779997862">"Salvaţi fotografia editată?"</string> + <string name="yes" msgid="5402582493291792293">"Da"</string> + <string name="no" msgid="5595408018304861875">"Nu"</string> + <string name="cancel" msgid="6286688759430767307">"Anulaţi"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Editate"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistic"</string> + <string name="color_group" msgid="3390757893475444688">"Culoare"</string> + <string name="exposure_group" msgid="7019148007708100078">"Expunere"</string> + <string name="fix_group" msgid="971450155810247383">"Remediere"</string> + <string name="autofix" msgid="1223859191856172755">"Mă simt norocos"</string> + <string name="crossprocess" msgid="4173724489001742342">"Suprapunere"</string> + <string name="documentary" msgid="50396326708699797">"Documentar"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"În două culori"</string> + <string name="filllight" msgid="2644989991700022526">"Lumină complet."</string> + <string name="fisheye" msgid="6037488646928998921">"Ochi de peşte"</string> + <string name="flip" msgid="2357692401826287480">"Răsturnare"</string> + <string name="grain" msgid="7487585304579789098">"Granulaţie film"</string> + <string name="grayscale" msgid="615169770671286699">"Tonuri de gri"</string> + <string name="highlight" msgid="3902653944386623972">"Evidenţieri"</string> + <string name="lomoish" msgid="7793824845892532976">"În stilul Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negativ"</string> + <string name="posterize" msgid="4139212359561383385">"Poster"</string> + <string name="redeye" msgid="4958448806369928239">"Ochi roşii"</string> + <string name="rotate" msgid="6607597269792373083">"Rotaţie"</string> + <string name="saturation" msgid="8621322012271169931">"Saturaţie"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Umbre"</string> + <string name="sharpen" msgid="8449662378104403230">"Clarificare"</string> + <string name="softfocus" msgid="6334228862566408303">"Defocalizare"</string> + <string name="straighten" msgid="5217801513491493491">"Îndreptare"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatură"</string> + <string name="tint" msgid="154435943863418434">"Haşură"</string> + <string name="vignette" msgid="7648125924662648282">"Vignetare"</string> + <string name="warmify" msgid="2404474974251014984">"Tonuri mai calde"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Desenaţi pe fotografie pentru a aplica efectul doodle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Trageţi o fotografie pentru a o răsturna"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Apăsaţi pentru a elimina ochii roşii"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Trageţi fotografia pentru a o roti"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Trageţi de fotografie pentru a o îndrepta"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-ru/strings.xml b/samples/PhotoEditor/res/values-ru/strings.xml new file mode 100644 index 0000000..f8f19e9 --- /dev/null +++ b/samples/PhotoEditor/res/values-ru/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Фотостудия"</string> + <string name="loading_failure" msgid="8575831322115054185">"Не удается загрузить фото для изменения"</string> + <string name="saving_failure" msgid="3116717307036082369">"При сохранении произошла ошибка"</string> + <string name="photo_saved" msgid="5093564498138145422">"Фото <xliff:g id="FILENAME">%s</xliff:g> сохранено"</string> + <string name="save_photo" msgid="3125109368779997862">"Сохранить изменения?"</string> + <string name="yes" msgid="5402582493291792293">"Да"</string> + <string name="no" msgid="5595408018304861875">"Нет"</string> + <string name="cancel" msgid="6286688759430767307">"Отмена"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Измененные"</string> + <string name="artistic_group" msgid="573091775825402562">"Художник"</string> + <string name="color_group" msgid="3390757893475444688">"Цвет"</string> + <string name="exposure_group" msgid="7019148007708100078">"Экспозиция"</string> + <string name="fix_group" msgid="971450155810247383">"Исправление"</string> + <string name="autofix" msgid="1223859191856172755">"Мне повезет!"</string> + <string name="crossprocess" msgid="4173724489001742342">"Кроссобработка"</string> + <string name="documentary" msgid="50396326708699797">"Документальные"</string> + <string name="doodle" msgid="1686409894518940990">"Подмалевок"</string> + <string name="duotone" msgid="8145893940788467106">"Двойной тон"</string> + <string name="filllight" msgid="2644989991700022526">"Осветление"</string> + <string name="fisheye" msgid="6037488646928998921">"Рыбий глаз"</string> + <string name="flip" msgid="2357692401826287480">"Отразить"</string> + <string name="grain" msgid="7487585304579789098">"Зернистость"</string> + <string name="grayscale" msgid="615169770671286699">"Оттенки серого"</string> + <string name="highlight" msgid="3902653944386623972">"Блики"</string> + <string name="lomoish" msgid="7793824845892532976">"В стиле Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Негатив"</string> + <string name="posterize" msgid="4139212359561383385">"Постеризация"</string> + <string name="redeye" msgid="4958448806369928239">"Красные глаза"</string> + <string name="rotate" msgid="6607597269792373083">"Поворот"</string> + <string name="saturation" msgid="8621322012271169931">"Насыщенность"</string> + <string name="sepia" msgid="7978093531824705601">"Сепия"</string> + <string name="shadow" msgid="8235188588101973090">"Затенение"</string> + <string name="sharpen" msgid="8449662378104403230">"Резкость"</string> + <string name="softfocus" msgid="6334228862566408303">"Мягкий фокус"</string> + <string name="straighten" msgid="5217801513491493491">"Выравнивание"</string> + <string name="temperature" msgid="3589958696423284897">"Температура"</string> + <string name="tint" msgid="154435943863418434">"Оттенок"</string> + <string name="vignette" msgid="7648125924662648282">"Виньетка"</string> + <string name="warmify" msgid="2404474974251014984">"Теплые тона"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Рисуйте на фото пальцем"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Чтобы отразить фото, перетащите его край"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Нажмите для устранения эффекта красных глаз"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Чтобы повернуть фото, перетащите его край"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Чтобы выровнять фото, перетащите его"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-sk/strings.xml b/samples/PhotoEditor/res/values-sk/strings.xml new file mode 100644 index 0000000..c6379d0 --- /dev/null +++ b/samples/PhotoEditor/res/values-sk/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Fotografiu nie je možné načítať na úpravy"</string> + <string name="saving_failure" msgid="3116717307036082369">"Pri ukladaní sa vyskytol problém"</string> + <string name="photo_saved" msgid="5093564498138145422">"Fotografie <xliff:g id="FILENAME">%s</xliff:g> boli uložené"</string> + <string name="save_photo" msgid="3125109368779997862">"Chcete upravenú fotografiu uložiť?"</string> + <string name="yes" msgid="5402582493291792293">"Áno"</string> + <string name="no" msgid="5595408018304861875">"Nie"</string> + <string name="cancel" msgid="6286688759430767307">"Zrušiť"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Upravené"</string> + <string name="artistic_group" msgid="573091775825402562">"Umelecké"</string> + <string name="color_group" msgid="3390757893475444688">"Farba"</string> + <string name="exposure_group" msgid="7019148007708100078">"Expozícia"</string> + <string name="fix_group" msgid="971450155810247383">"Korekcia"</string> + <string name="autofix" msgid="1223859191856172755">"Skúsim šťastie"</string> + <string name="crossprocess" msgid="4173724489001742342">"Prelínanie"</string> + <string name="documentary" msgid="50396326708699797">"Dokument"</string> + <string name="doodle" msgid="1686409894518940990">"Kreslenie"</string> + <string name="duotone" msgid="8145893940788467106">"Dvojtónový efekt"</string> + <string name="filllight" msgid="2644989991700022526">"Zad. osvetlenie"</string> + <string name="fisheye" msgid="6037488646928998921">"Rybie oko"</string> + <string name="flip" msgid="2357692401826287480">"Prevrátenie"</string> + <string name="grain" msgid="7487585304579789098">"Zrnitý film"</string> + <string name="grayscale" msgid="615169770671286699">"Stupne sivej"</string> + <string name="highlight" msgid="3902653944386623972">"Prisvietenie"</string> + <string name="lomoish" msgid="7793824845892532976">"Štýl Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negatív"</string> + <string name="posterize" msgid="4139212359561383385">"Posterizácia"</string> + <string name="redeye" msgid="4958448806369928239">"Červené oči"</string> + <string name="rotate" msgid="6607597269792373083">"Otočenie"</string> + <string name="saturation" msgid="8621322012271169931">"Sýtosť"</string> + <string name="sepia" msgid="7978093531824705601">"Sépiové farby"</string> + <string name="shadow" msgid="8235188588101973090">"Tiene"</string> + <string name="sharpen" msgid="8449662378104403230">"Zaostrenie"</string> + <string name="softfocus" msgid="6334228862566408303">"Jemné rozostr."</string> + <string name="straighten" msgid="5217801513491493491">"Vyrovnanie"</string> + <string name="temperature" msgid="3589958696423284897">"Teplota"</string> + <string name="tint" msgid="154435943863418434">"Tónovanie"</string> + <string name="vignette" msgid="7648125924662648282">"Medailónik"</string> + <string name="warmify" msgid="2404474974251014984">"Teplejšie farby"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Na fotografii môžete kresliť prstom"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Pretiahnutím prstom fotografiu prevrátite"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Klepnutím odstráňte efekt červených očí"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Potiahnutím prstom fotografiu otočíte"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Potiahnutím prstom fotografiu vyrovnáte"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-sl/strings.xml b/samples/PhotoEditor/res/values-sl/strings.xml new file mode 100644 index 0000000..1f2b906 --- /dev/null +++ b/samples/PhotoEditor/res/values-sl/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Fotografije ni mogoče naložiti za urejanje"</string> + <string name="saving_failure" msgid="3116717307036082369">"Med shranjevanjem je prišlo do težave"</string> + <string name="photo_saved" msgid="5093564498138145422">"Datoteka <xliff:g id="FILENAME">%s</xliff:g> je shranjena"</string> + <string name="save_photo" msgid="3125109368779997862">"Želite shraniti urejene fotografije?"</string> + <string name="yes" msgid="5402582493291792293">"Da"</string> + <string name="no" msgid="5595408018304861875">"Ne"</string> + <string name="cancel" msgid="6286688759430767307">"Prekliči"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Urejeno"</string> + <string name="artistic_group" msgid="573091775825402562">"Umetniško"</string> + <string name="color_group" msgid="3390757893475444688">"Barva"</string> + <string name="exposure_group" msgid="7019148007708100078">"Osvetlitev"</string> + <string name="fix_group" msgid="971450155810247383">"Popravki"</string> + <string name="autofix" msgid="1223859191856172755">"Samodejno"</string> + <string name="crossprocess" msgid="4173724489001742342">"Navzkr. obdel."</string> + <string name="documentary" msgid="50396326708699797">"Dokumentarno"</string> + <string name="doodle" msgid="1686409894518940990">"Čačka"</string> + <string name="duotone" msgid="8145893940788467106">"Dvotonsko"</string> + <string name="filllight" msgid="2644989991700022526">"Dosvetlitev"</string> + <string name="fisheye" msgid="6037488646928998921">"Ribje oko"</string> + <string name="flip" msgid="2357692401826287480">"Obrnjeno"</string> + <string name="grain" msgid="7487585304579789098">"Zrnatost filma"</string> + <string name="grayscale" msgid="615169770671286699">"Sivine"</string> + <string name="highlight" msgid="3902653944386623972">"Poudarki"</string> + <string name="lomoish" msgid="7793824845892532976">"Slog lomo"</string> + <string name="negative" msgid="1985508917342811252">"Negativ"</string> + <string name="posterize" msgid="4139212359561383385">"Poster"</string> + <string name="redeye" msgid="4958448806369928239">"Rdeče oči"</string> + <string name="rotate" msgid="6607597269792373083">"Zasukaj"</string> + <string name="saturation" msgid="8621322012271169931">"Nasičenost"</string> + <string name="sepia" msgid="7978093531824705601">"Sepija"</string> + <string name="shadow" msgid="8235188588101973090">"Sence"</string> + <string name="sharpen" msgid="8449662378104403230">"Izostri"</string> + <string name="softfocus" msgid="6334228862566408303">"Megleno"</string> + <string name="straighten" msgid="5217801513491493491">"Poravnavanje"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Obarvanje"</string> + <string name="vignette" msgid="7648125924662648282">"Vinjeta"</string> + <string name="warmify" msgid="2404474974251014984">"Toplejši toni"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Povlecite po fotografiji za prostoročno risanje"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Povlecite fotografijo, da jo obrnete"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Tapnite, da odstranite rdeče oči"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Povlecite fotografijo, da jo zavrtite"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Povlecite fotografijo, da jo poravnate"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-sr/strings.xml b/samples/PhotoEditor/res/values-sr/strings.xml new file mode 100644 index 0000000..67cef0f --- /dev/null +++ b/samples/PhotoEditor/res/values-sr/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Фото-студио"</string> + <string name="loading_failure" msgid="8575831322115054185">"Није могуће учитати фотографију за измену"</string> + <string name="saving_failure" msgid="3116717307036082369">"Дошло је до проблема приликом чувања"</string> + <string name="photo_saved" msgid="5093564498138145422">"Сачувана је датотека <xliff:g id="FILENAME">%s</xliff:g>"</string> + <string name="save_photo" msgid="3125109368779997862">"Желите ли да сачувате измењену фотографију?"</string> + <string name="yes" msgid="5402582493291792293">"Да"</string> + <string name="no" msgid="5595408018304861875">"Не"</string> + <string name="cancel" msgid="6286688759430767307">"Откажи"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Измењено"</string> + <string name="artistic_group" msgid="573091775825402562">"Уметнички"</string> + <string name="color_group" msgid="3390757893475444688">"Боја"</string> + <string name="exposure_group" msgid="7019148007708100078">"Експозиција"</string> + <string name="fix_group" msgid="971450155810247383">"Фиксирање"</string> + <string name="autofix" msgid="1223859191856172755">"Аутоматски"</string> + <string name="crossprocess" msgid="4173724489001742342">"Унакрсна обрада"</string> + <string name="documentary" msgid="50396326708699797">"Документарни"</string> + <string name="doodle" msgid="1686409894518940990">"Дудл логотип"</string> + <string name="duotone" msgid="8145893940788467106">"Дуо-тон"</string> + <string name="filllight" msgid="2644989991700022526">"Светлина"</string> + <string name="fisheye" msgid="6037488646928998921">"Рибље око"</string> + <string name="flip" msgid="2357692401826287480">"Обрни"</string> + <string name="grain" msgid="7487585304579789098">"Зрнастост филма"</string> + <string name="grayscale" msgid="615169770671286699">"Црно-бело"</string> + <string name="highlight" msgid="3902653944386623972">"Истакнуте ставке"</string> + <string name="lomoish" msgid="7793824845892532976">"Ломографски"</string> + <string name="negative" msgid="1985508917342811252">"Негатив"</string> + <string name="posterize" msgid="4139212359561383385">"Постеризуј"</string> + <string name="redeye" msgid="4958448806369928239">"Црвене очи"</string> + <string name="rotate" msgid="6607597269792373083">"Ротирај"</string> + <string name="saturation" msgid="8621322012271169931">"Засићење"</string> + <string name="sepia" msgid="7978093531824705601">"Сепија"</string> + <string name="shadow" msgid="8235188588101973090">"Сенке"</string> + <string name="sharpen" msgid="8449662378104403230">"Изоштри"</string> + <string name="softfocus" msgid="6334228862566408303">"Меки фокус"</string> + <string name="straighten" msgid="5217801513491493491">"Исправи"</string> + <string name="temperature" msgid="3589958696423284897">"Температура"</string> + <string name="tint" msgid="154435943863418434">"Сенка"</string> + <string name="vignette" msgid="7648125924662648282">"Вињета"</string> + <string name="warmify" msgid="2404474974251014984">"Топлије боје"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Превуците слику на дудл логотип"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Превуците фотографију да бисте је окренули"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Додирните да бисте уклонили ефекат црвених очију"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Превуците фотографију да бисте је ротирали"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Превуците фотографију да бисте је исправили"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-sv/strings.xml b/samples/PhotoEditor/res/values-sv/strings.xml new file mode 100644 index 0000000..07091f1 --- /dev/null +++ b/samples/PhotoEditor/res/values-sv/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Fotostudio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Kan inte läsa in fotot för redigering"</string> + <string name="saving_failure" msgid="3116717307036082369">"Det gick inte att spara"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> sparades"</string> + <string name="save_photo" msgid="3125109368779997862">"Spara redigerat foto?"</string> + <string name="yes" msgid="5402582493291792293">"Ja"</string> + <string name="no" msgid="5595408018304861875">"Nej"</string> + <string name="cancel" msgid="6286688759430767307">"Avbryt"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Redigerade"</string> + <string name="artistic_group" msgid="573091775825402562">"Konstnärlig"</string> + <string name="color_group" msgid="3390757893475444688">"Färg"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exponering"</string> + <string name="fix_group" msgid="971450155810247383">"Korrigera"</string> + <string name="autofix" msgid="1223859191856172755">"Jag har tur"</string> + <string name="crossprocess" msgid="4173724489001742342">"Cross Process"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentär"</string> + <string name="doodle" msgid="1686409894518940990">"Klotter"</string> + <string name="duotone" msgid="8145893940788467106">"Duoton"</string> + <string name="filllight" msgid="2644989991700022526">"Fyll belysning"</string> + <string name="fisheye" msgid="6037488646928998921">"Fisheye"</string> + <string name="flip" msgid="2357692401826287480">"Vänd"</string> + <string name="grain" msgid="7487585304579789098">"Filmkornighet"</string> + <string name="grayscale" msgid="615169770671286699">"Gråskala"</string> + <string name="highlight" msgid="3902653944386623972">"Högdager"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo-stil"</string> + <string name="negative" msgid="1985508917342811252">"Negativ"</string> + <string name="posterize" msgid="4139212359561383385">"Färgreduktion"</string> + <string name="redeye" msgid="4958448806369928239">"Röda ögon"</string> + <string name="rotate" msgid="6607597269792373083">"Rotera"</string> + <string name="saturation" msgid="8621322012271169931">"Mättnad"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Skuggor"</string> + <string name="sharpen" msgid="8449662378104403230">"Skarpare"</string> + <string name="softfocus" msgid="6334228862566408303">"Minska fokus"</string> + <string name="straighten" msgid="5217801513491493491">"Räta ut"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatur"</string> + <string name="tint" msgid="154435943863418434">"Ton"</string> + <string name="vignette" msgid="7648125924662648282">"Vignette"</string> + <string name="warmify" msgid="2404474974251014984">"Värme"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Rita på bilden om du vill doodle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Tryck och dra bilden om du vill vända den"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Knacka lätt om du vill ta bort röda ögon"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Tryck och dra bilden om du vill rotera den"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Tryck och dra bilden om du vill räta upp den"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-th/strings.xml b/samples/PhotoEditor/res/values-th/strings.xml new file mode 100644 index 0000000..dcd2853 --- /dev/null +++ b/samples/PhotoEditor/res/values-th/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"สตูดิโอถ่ายภาพ"</string> + <string name="loading_failure" msgid="8575831322115054185">"ไม่สามารถโหลดภาพเพื่อแก้ไข"</string> + <string name="saving_failure" msgid="3116717307036082369">"เกิดปัญหาในระหว่างการบันทึก"</string> + <string name="photo_saved" msgid="5093564498138145422">"บันทึก <xliff:g id="FILENAME">%s</xliff:g> แล้ว"</string> + <string name="save_photo" msgid="3125109368779997862">"บันทึกภาพที่แก้ไขหรือไม่"</string> + <string name="yes" msgid="5402582493291792293">"ใช่"</string> + <string name="no" msgid="5595408018304861875">"ไม่"</string> + <string name="cancel" msgid="6286688759430767307">"ยกเลิก"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"แก้ไขแล้ว"</string> + <string name="artistic_group" msgid="573091775825402562">"ศิลปะ"</string> + <string name="color_group" msgid="3390757893475444688">"สี"</string> + <string name="exposure_group" msgid="7019148007708100078">"การรับแสง"</string> + <string name="fix_group" msgid="971450155810247383">"คงที่"</string> + <string name="autofix" msgid="1223859191856172755">"ดีใจจัง"</string> + <string name="crossprocess" msgid="4173724489001742342">"ครอสโพรเซส"</string> + <string name="documentary" msgid="50396326708699797">"สารคดี"</string> + <string name="doodle" msgid="1686409894518940990">"doodle"</string> + <string name="duotone" msgid="8145893940788467106">"ดูโอโทน"</string> + <string name="filllight" msgid="2644989991700022526">"เติมแสง"</string> + <string name="fisheye" msgid="6037488646928998921">"ฟิชอาย"</string> + <string name="flip" msgid="2357692401826287480">"ฟลิป"</string> + <string name="grain" msgid="7487585304579789098">"เนื้อฟิล์ม"</string> + <string name="grayscale" msgid="615169770671286699">"โทนสีเทา"</string> + <string name="highlight" msgid="3902653944386623972">"ไฮไลต์"</string> + <string name="lomoish" msgid="7793824845892532976">"แนวโลโม"</string> + <string name="negative" msgid="1985508917342811252">"สีตรงข้าม"</string> + <string name="posterize" msgid="4139212359561383385">"ลดจำนวนสีในภาพ"</string> + <string name="redeye" msgid="4958448806369928239">"ตาแดง"</string> + <string name="rotate" msgid="6607597269792373083">"หมุน"</string> + <string name="saturation" msgid="8621322012271169931">"ความอิ่มตัว"</string> + <string name="sepia" msgid="7978093531824705601">"ซีเปีย"</string> + <string name="shadow" msgid="8235188588101973090">"เงา"</string> + <string name="sharpen" msgid="8449662378104403230">"ทำให้ชัด"</string> + <string name="softfocus" msgid="6334228862566408303">"ซอฟต์โฟกัส"</string> + <string name="straighten" msgid="5217801513491493491">"ทำให้ตรง"</string> + <string name="temperature" msgid="3589958696423284897">"อุณหภูมิ"</string> + <string name="tint" msgid="154435943863418434">"แต้มสี"</string> + <string name="vignette" msgid="7648125924662648282">"วิกเน็ตต์"</string> + <string name="warmify" msgid="2404474974251014984">"ทำให้ภาพดูอบอุ่นขึ้น"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"วาดบนภาพเพื่อ doodle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"ลากภาพเพื่อพลิก"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"แตะเพื่อลบตาแดง"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"ลากภาพเพื่อหมุน"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"ลากภาพเพื่อยืดให้ตรง"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-tl/strings.xml b/samples/PhotoEditor/res/values-tl/strings.xml new file mode 100644 index 0000000..bdfd5d5 --- /dev/null +++ b/samples/PhotoEditor/res/values-tl/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Hindi ma-load ang larawan para sa pag-edit"</string> + <string name="saving_failure" msgid="3116717307036082369">"May naganap na problema habang nagse-save"</string> + <string name="photo_saved" msgid="5093564498138145422">"Na-save ang <xliff:g id="FILENAME">%s</xliff:g>"</string> + <string name="save_photo" msgid="3125109368779997862">"I-save ang na-edit na larawan?"</string> + <string name="yes" msgid="5402582493291792293">"Oo"</string> + <string name="no" msgid="5595408018304861875">"Hindi"</string> + <string name="cancel" msgid="6286688759430767307">"Kanselahin"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Na-edit"</string> + <string name="artistic_group" msgid="573091775825402562">"Artistic"</string> + <string name="color_group" msgid="3390757893475444688">"Kulay"</string> + <string name="exposure_group" msgid="7019148007708100078">"Exposure"</string> + <string name="fix_group" msgid="971450155810247383">"Ayusin"</string> + <string name="autofix" msgid="1223859191856172755">"Masuwerte"</string> + <string name="crossprocess" msgid="4173724489001742342">"I-cross-process"</string> + <string name="documentary" msgid="50396326708699797">"Dokumentaryo"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Duo-tone"</string> + <string name="filllight" msgid="2644989991700022526">"Pampunong Ilaw"</string> + <string name="fisheye" msgid="6037488646928998921">"Fisheye"</string> + <string name="flip" msgid="2357692401826287480">"Baliktarin"</string> + <string name="grain" msgid="7487585304579789098">"Film Grain"</string> + <string name="grayscale" msgid="615169770671286699">"Grayscale"</string> + <string name="highlight" msgid="3902653944386623972">"Mga Highlight"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo-ish"</string> + <string name="negative" msgid="1985508917342811252">"Negative"</string> + <string name="posterize" msgid="4139212359561383385">"I-posterize"</string> + <string name="redeye" msgid="4958448806369928239">"Pulang Mata"</string> + <string name="rotate" msgid="6607597269792373083">"Paikutin"</string> + <string name="saturation" msgid="8621322012271169931">"Saturation"</string> + <string name="sepia" msgid="7978093531824705601">"Sepia"</string> + <string name="shadow" msgid="8235188588101973090">"Mga Shadow"</string> + <string name="sharpen" msgid="8449662378104403230">"I-sharpen"</string> + <string name="softfocus" msgid="6334228862566408303">"Soft Focus"</string> + <string name="straighten" msgid="5217801513491493491">"Ituwid"</string> + <string name="temperature" msgid="3589958696423284897">"Temperatura"</string> + <string name="tint" msgid="154435943863418434">"Tint"</string> + <string name="vignette" msgid="7648125924662648282">"Vignette"</string> + <string name="warmify" msgid="2404474974251014984">"Gawing Warm"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Gumuhit sa larawan upang mag-doodle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"I-drag ang larawan upang i-flip ito"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Tapikin upang alisin ang mga pulang mata"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"I-drag ang larawan upang i-rotate ito"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"I-drag ang larawan upang iunat ito"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-tr/strings.xml b/samples/PhotoEditor/res/values-tr/strings.xml new file mode 100644 index 0000000..b3df612 --- /dev/null +++ b/samples/PhotoEditor/res/values-tr/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Fotoğraf Stüdyosu"</string> + <string name="loading_failure" msgid="8575831322115054185">"Fotoğraf düzenlenmek üzere yüklenemiyor"</string> + <string name="saving_failure" msgid="3116717307036082369">"Kaydederken sorun oluştu"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> kaydedildi"</string> + <string name="save_photo" msgid="3125109368779997862">"Düzenlenmiş fotoğraf kaydedilsin mi?"</string> + <string name="yes" msgid="5402582493291792293">"Evet"</string> + <string name="no" msgid="5595408018304861875">"Hayır"</string> + <string name="cancel" msgid="6286688759430767307">"İptal"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Düzenlendi"</string> + <string name="artistic_group" msgid="573091775825402562">"Sanatsal"</string> + <string name="color_group" msgid="3390757893475444688">"Renk"</string> + <string name="exposure_group" msgid="7019148007708100078">"Pozlama"</string> + <string name="fix_group" msgid="971450155810247383">"Düzelt"</string> + <string name="autofix" msgid="1223859191856172755">"Şanslı Hissdyrm"</string> + <string name="crossprocess" msgid="4173724489001742342">"Çapraz Banyo"</string> + <string name="documentary" msgid="50396326708699797">"Belgesel"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"İki tonlu"</string> + <string name="filllight" msgid="2644989991700022526">"Dolgu Işığı"</string> + <string name="fisheye" msgid="6037488646928998921">"Balıkgözü"</string> + <string name="flip" msgid="2357692401826287480">"Çevir"</string> + <string name="grain" msgid="7487585304579789098">"Film Greni"</string> + <string name="grayscale" msgid="615169770671286699">"Gri Tonlama"</string> + <string name="highlight" msgid="3902653944386623972">"Parlak noktalar"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo Tarzı"</string> + <string name="negative" msgid="1985508917342811252">"Negatif"</string> + <string name="posterize" msgid="4139212359561383385">"Poster Efkt Uyg"</string> + <string name="redeye" msgid="4958448806369928239">"Kırmızı Göz"</string> + <string name="rotate" msgid="6607597269792373083">"Döndür"</string> + <string name="saturation" msgid="8621322012271169931">"Doygunluk"</string> + <string name="sepia" msgid="7978093531824705601">"Sepya Tonu"</string> + <string name="shadow" msgid="8235188588101973090">"Gölgeler"</string> + <string name="sharpen" msgid="8449662378104403230">"Keskinleştir"</string> + <string name="softfocus" msgid="6334228862566408303">"Yumuşak Odak"</string> + <string name="straighten" msgid="5217801513491493491">"Düzelt"</string> + <string name="temperature" msgid="3589958696423284897">"Sıcaklık"</string> + <string name="tint" msgid="154435943863418434">"Tonlama"</string> + <string name="vignette" msgid="7648125924662648282">"Vinyet"</string> + <string name="warmify" msgid="2404474974251014984">"Sıcak Göster"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Doodle için fotoğrafın üzerinde çizin"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Çevirmek için fotoğrafı sürükleyin"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Kırmızı gözleri kaldırmak için hafifçe vurun"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Döndürmek için fotoğrafı sürükleyin"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Düzleştirmek için fotoğrafı sürükleyin"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-uk/strings.xml b/samples/PhotoEditor/res/values-uk/strings.xml new file mode 100644 index 0000000..8c71d57 --- /dev/null +++ b/samples/PhotoEditor/res/values-uk/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"Неможливо завантажити фотографію для редагування"</string> + <string name="saving_failure" msgid="3116717307036082369">"Під час збереження виникла проблема"</string> + <string name="photo_saved" msgid="5093564498138145422">"Файл \"<xliff:g id="FILENAME">%s</xliff:g>\" збережено"</string> + <string name="save_photo" msgid="3125109368779997862">"Зберегти відредаговану фотографію?"</string> + <string name="yes" msgid="5402582493291792293">"Так"</string> + <string name="no" msgid="5595408018304861875">"Ні"</string> + <string name="cancel" msgid="6286688759430767307">"Скасувати"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Редаговано"</string> + <string name="artistic_group" msgid="573091775825402562">"Художнє фото"</string> + <string name="color_group" msgid="3390757893475444688">"Колір"</string> + <string name="exposure_group" msgid="7019148007708100078">"Експозиція"</string> + <string name="fix_group" msgid="971450155810247383">"Виправлення"</string> + <string name="autofix" msgid="1223859191856172755">"Мені пощастить"</string> + <string name="crossprocess" msgid="4173724489001742342">"Крос-процес"</string> + <string name="documentary" msgid="50396326708699797">"Чорно-білі тони"</string> + <string name="doodle" msgid="1686409894518940990">"Doodle"</string> + <string name="duotone" msgid="8145893940788467106">"Два тони"</string> + <string name="filllight" msgid="2644989991700022526">"Доповн. світло"</string> + <string name="fisheye" msgid="6037488646928998921">"\"Риб’яче око\""</string> + <string name="flip" msgid="2357692401826287480">"Перевернути"</string> + <string name="grain" msgid="7487585304579789098">"Зернистість плівки"</string> + <string name="grayscale" msgid="615169770671286699">"Сірі тони"</string> + <string name="highlight" msgid="3902653944386623972">"Світлові ефекти"</string> + <string name="lomoish" msgid="7793824845892532976">"Ломо-ефект"</string> + <string name="negative" msgid="1985508917342811252">"Негатив"</string> + <string name="posterize" msgid="4139212359561383385">"Ефект плаката"</string> + <string name="redeye" msgid="4958448806369928239">"Червоні очі"</string> + <string name="rotate" msgid="6607597269792373083">"Обертання"</string> + <string name="saturation" msgid="8621322012271169931">"Насиченість"</string> + <string name="sepia" msgid="7978093531824705601">"Сепія"</string> + <string name="shadow" msgid="8235188588101973090">"Тіні"</string> + <string name="sharpen" msgid="8449662378104403230">"Різкість"</string> + <string name="softfocus" msgid="6334228862566408303">"М’який фокус"</string> + <string name="straighten" msgid="5217801513491493491">"Вирівняти"</string> + <string name="temperature" msgid="3589958696423284897">"Температура"</string> + <string name="tint" msgid="154435943863418434">"Відтінок"</string> + <string name="vignette" msgid="7648125924662648282">"Віньєтка"</string> + <string name="warmify" msgid="2404474974251014984">"Тепліші тони"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Малюйте на фото, щоб створити doodle"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Перетягніть фото, щоб перевернути його"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Натисніть, щоб усунути ефект червоних очей"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Перетягніть фото, щоб обертати його"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Перетягніть фото, щоб вирівняти його"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-vi/strings.xml b/samples/PhotoEditor/res/values-vi/strings.xml new file mode 100644 index 0000000..92f119f --- /dev/null +++ b/samples/PhotoEditor/res/values-vi/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Studio ảnh"</string> + <string name="loading_failure" msgid="8575831322115054185">"Không thể tải ảnh để chỉnh sửa"</string> + <string name="saving_failure" msgid="3116717307036082369">"Đã xảy ra lỗi trong khi lưu"</string> + <string name="photo_saved" msgid="5093564498138145422">"Đã lưu <xliff:g id="FILENAME">%s</xliff:g>"</string> + <string name="save_photo" msgid="3125109368779997862">"Lưu ảnh đã chỉnh sửa?"</string> + <string name="yes" msgid="5402582493291792293">"Có"</string> + <string name="no" msgid="5595408018304861875">"Không"</string> + <string name="cancel" msgid="6286688759430767307">"Hủy"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"Đã chỉnh sửa"</string> + <string name="artistic_group" msgid="573091775825402562">"Nghệ thuật"</string> + <string name="color_group" msgid="3390757893475444688">"Màu sắc"</string> + <string name="exposure_group" msgid="7019148007708100078">"Phơi sáng"</string> + <string name="fix_group" msgid="971450155810247383">"Cố định"</string> + <string name="autofix" msgid="1223859191856172755">"Tự chỉnh ph.sáng"</string> + <string name="crossprocess" msgid="4173724489001742342">"Tạo màu sắc khác lạ"</string> + <string name="documentary" msgid="50396326708699797">"Phim tài liệu"</string> + <string name="doodle" msgid="1686409894518940990">"Hình vẽ nguệch ngoạc"</string> + <string name="duotone" msgid="8145893940788467106">"Có hai màu"</string> + <string name="filllight" msgid="2644989991700022526">"Tô sáng"</string> + <string name="fisheye" msgid="6037488646928998921">"Mắt cá"</string> + <string name="flip" msgid="2357692401826287480">"Lật"</string> + <string name="grain" msgid="7487585304579789098">"Hiệu ứng hạt mỏng"</string> + <string name="grayscale" msgid="615169770671286699">"Thang màu xám"</string> + <string name="highlight" msgid="3902653944386623972">"Thêm điểm sáng"</string> + <string name="lomoish" msgid="7793824845892532976">"Kiểu Lomo"</string> + <string name="negative" msgid="1985508917342811252">"Tạo âm bản"</string> + <string name="posterize" msgid="4139212359561383385">"Ảnh áp phích"</string> + <string name="redeye" msgid="4958448806369928239">"Mắt đỏ"</string> + <string name="rotate" msgid="6607597269792373083">"Xoay"</string> + <string name="saturation" msgid="8621322012271169931">"Bão hòa"</string> + <string name="sepia" msgid="7978093531824705601">"Nâu đỏ"</string> + <string name="shadow" msgid="8235188588101973090">"Bóng"</string> + <string name="sharpen" msgid="8449662378104403230">"Làm sắc nét"</string> + <string name="softfocus" msgid="6334228862566408303">"Tiêu điểm mềm"</string> + <string name="straighten" msgid="5217801513491493491">"Làm thẳng"</string> + <string name="temperature" msgid="3589958696423284897">"Nhiệt độ"</string> + <string name="tint" msgid="154435943863418434">"Phủ màu"</string> + <string name="vignette" msgid="7648125924662648282">"Làm mờ nét ảnh"</string> + <string name="warmify" msgid="2404474974251014984">"Làm nóng"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"Kéo trên ảnh để vẽ ngoạch ngoạc"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"Kéo ảnh để lật"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"Chạm để loại bỏ mắt đỏ"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"Kéo ảnh để xoay"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"Kéo ảnh để sắp thẳng"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-zh-rCN/strings.xml b/samples/PhotoEditor/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000..50c7cc3 --- /dev/null +++ b/samples/PhotoEditor/res/values-zh-rCN/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"照相馆"</string> + <string name="loading_failure" msgid="8575831322115054185">"无法加载照片以供修改"</string> + <string name="saving_failure" msgid="3116717307036082369">"保存时出现问题"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g>已保存"</string> + <string name="save_photo" msgid="3125109368779997862">"要保存已修改的照片吗?"</string> + <string name="yes" msgid="5402582493291792293">"是"</string> + <string name="no" msgid="5595408018304861875">"否"</string> + <string name="cancel" msgid="6286688759430767307">"取消"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"已修改"</string> + <string name="artistic_group" msgid="573091775825402562">"艺术效果"</string> + <string name="color_group" msgid="3390757893475444688">"颜色"</string> + <string name="exposure_group" msgid="7019148007708100078">"曝光"</string> + <string name="fix_group" msgid="971450155810247383">"修正"</string> + <string name="autofix" msgid="1223859191856172755">"修正曝光"</string> + <string name="crossprocess" msgid="4173724489001742342">"交叉冲印"</string> + <string name="documentary" msgid="50396326708699797">"纪实"</string> + <string name="doodle" msgid="1686409894518940990">"涂鸦"</string> + <string name="duotone" msgid="8145893940788467106">"双色"</string> + <string name="filllight" msgid="2644989991700022526">"补光"</string> + <string name="fisheye" msgid="6037488646928998921">"鱼眼镜头"</string> + <string name="flip" msgid="2357692401826287480">"翻转"</string> + <string name="grain" msgid="7487585304579789098">"胶片颗粒"</string> + <string name="grayscale" msgid="615169770671286699">"灰度"</string> + <string name="highlight" msgid="3902653944386623972">"加亮区"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo 风格"</string> + <string name="negative" msgid="1985508917342811252">"反色"</string> + <string name="posterize" msgid="4139212359561383385">"色调分离"</string> + <string name="redeye" msgid="4958448806369928239">"红眼"</string> + <string name="rotate" msgid="6607597269792373083">"旋转"</string> + <string name="saturation" msgid="8621322012271169931">"饱和度"</string> + <string name="sepia" msgid="7978093531824705601">"深褐色"</string> + <string name="shadow" msgid="8235188588101973090">"阴影"</string> + <string name="sharpen" msgid="8449662378104403230">"锐化"</string> + <string name="softfocus" msgid="6334228862566408303">"柔焦"</string> + <string name="straighten" msgid="5217801513491493491">"拉直"</string> + <string name="temperature" msgid="3589958696423284897">"色温"</string> + <string name="tint" msgid="154435943863418434">"着色"</string> + <string name="vignette" msgid="7648125924662648282">"晕影"</string> + <string name="warmify" msgid="2404474974251014984">"暖色化"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"在照片上绘制即可涂鸦"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"拖动照片可将其翻转"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"点按可消除红眼"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"拖动照片可将其旋转"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"拖动照片可将其拉直"</string> +</resources> diff --git a/samples/PhotoEditor/res/values-zh-rTW/strings.xml b/samples/PhotoEditor/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..aada7e2 --- /dev/null +++ b/samples/PhotoEditor/res/values-zh-rTW/strings.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2010 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name" msgid="6794833895507358569">"Photo Studio"</string> + <string name="loading_failure" msgid="8575831322115054185">"無法載入要編輯的相片"</string> + <string name="saving_failure" msgid="3116717307036082369">"儲存時發生問題"</string> + <string name="photo_saved" msgid="5093564498138145422">"<xliff:g id="FILENAME">%s</xliff:g> 已儲存"</string> + <string name="save_photo" msgid="3125109368779997862">"要儲存已編輯的相片嗎?"</string> + <string name="yes" msgid="5402582493291792293">"是"</string> + <string name="no" msgid="5595408018304861875">"否"</string> + <string name="cancel" msgid="6286688759430767307">"取消"</string> + <string name="edited_photo_bucket_name" msgid="3777746536831799890">"已編輯"</string> + <string name="artistic_group" msgid="573091775825402562">"藝術"</string> + <string name="color_group" msgid="3390757893475444688">"色彩"</string> + <string name="exposure_group" msgid="7019148007708100078">"曝光"</string> + <string name="fix_group" msgid="971450155810247383">"修正"</string> + <string name="autofix" msgid="1223859191856172755">"好幸運"</string> + <string name="crossprocess" msgid="4173724489001742342">"融合處理"</string> + <string name="documentary" msgid="50396326708699797">"黑白紀錄片"</string> + <string name="doodle" msgid="1686409894518940990">"塗鴉"</string> + <string name="duotone" msgid="8145893940788467106">"雙色調"</string> + <string name="filllight" msgid="2644989991700022526">"調整亮度"</string> + <string name="fisheye" msgid="6037488646928998921">"魚眼"</string> + <string name="flip" msgid="2357692401826287480">"翻轉"</string> + <string name="grain" msgid="7487585304579789098">"膠片顆粒"</string> + <string name="grayscale" msgid="615169770671286699">"灰階"</string> + <string name="highlight" msgid="3902653944386623972">"強光"</string> + <string name="lomoish" msgid="7793824845892532976">"Lomo 風格"</string> + <string name="negative" msgid="1985508917342811252">"負片"</string> + <string name="posterize" msgid="4139212359561383385">"色調分離"</string> + <string name="redeye" msgid="4958448806369928239">"紅眼"</string> + <string name="rotate" msgid="6607597269792373083">"旋轉"</string> + <string name="saturation" msgid="8621322012271169931">"飽和度"</string> + <string name="sepia" msgid="7978093531824705601">"深褐色"</string> + <string name="shadow" msgid="8235188588101973090">"陰影"</string> + <string name="sharpen" msgid="8449662378104403230">"銳化"</string> + <string name="softfocus" msgid="6334228862566408303">"柔焦"</string> + <string name="straighten" msgid="5217801513491493491">"拉正"</string> + <string name="temperature" msgid="3589958696423284897">"色溫"</string> + <string name="tint" msgid="154435943863418434">"著色"</string> + <string name="vignette" msgid="7648125924662648282">"暈影"</string> + <string name="warmify" msgid="2404474974251014984">"加強暖色"</string> + <string name="doodle_tooltip" msgid="2902117272374362915">"在相片上畫圖即可塗鴉"</string> + <string name="flip_tooltip" msgid="2700943256714731737">"拖曳照片即可翻轉"</string> + <string name="redeye_tooltip" msgid="9112774042113471358">"輕按即可消除紅眼"</string> + <string name="rotate_tooltip" msgid="7008602969130734229">"拖曳照片即可旋轉"</string> + <string name="straighten_tooltip" msgid="4846317027139212339">"拖曳照片即可拉正"</string> +</resources> diff --git a/samples/PhotoEditor/res/values/arrays.xml b/samples/PhotoEditor/res/values/arrays.xml new file mode 100644 index 0000000..9877b98 --- /dev/null +++ b/samples/PhotoEditor/res/values/arrays.xml @@ -0,0 +1,335 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<resources> + <string-array name="autofix_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="autofix_icons"> + <item>@drawable/autofix_off</item> + <item>@drawable/autofix_on</item> + </array> + + <string-array name="crop_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="crop_icons"> + <item>@drawable/crop_off</item> + <item>@drawable/crop_on</item> + </array> + + <string-array name="crossprocess_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="crossprocess_icons"> + <item>@drawable/crossprocess_off</item> + <item>@drawable/crossprocess_on</item> + </array> + + <string-array name="documentary_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="documentary_icons"> + <item>@drawable/documentary_off</item> + <item>@drawable/documentary_on</item> + </array> + + <string-array name="doodle_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="doodle_icons"> + <item>@drawable/doodle_off</item> + <item>@drawable/doodle_on</item> + </array> + + <string-array name="duotone_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="duotone_icons"> + <item>@drawable/duotone_off</item> + <item>@drawable/duotone_on</item> + </array> + + <string-array name="filllight_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="filllight_icons"> + <item>@drawable/filllight_off</item> + <item>@drawable/filllight_on</item> + </array> + + <string-array name="fisheye_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="fisheye_icons"> + <item>@drawable/fisheye_off</item> + <item>@drawable/fisheye_on</item> + </array> + + <string-array name="flip_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="flip_icons"> + <item>@drawable/flip_off</item> + <item>@drawable/flip_on</item> + </array> + + <string-array name="grain_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="grain_icons"> + <item>@drawable/grain_off</item> + <item>@drawable/grain_on</item> + </array> + + <string-array name="grayscale_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="grayscale_icons"> + <item>@drawable/grayscale_off</item> + <item>@drawable/grayscale_on</item> + </array> + + <string-array name="highlight_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="highlight_icons"> + <item>@drawable/highlight_off</item> + <item>@drawable/highlight_on</item> + </array> + + <string-array name="lomoish_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="lomoish_icons"> + <item>@drawable/lomoish_off</item> + <item>@drawable/lomoish_on</item> + </array> + + <string-array name="negative_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="negative_icons"> + <item>@drawable/negative_off</item> + <item>@drawable/negative_on</item> + </array> + + <string-array name="posterize_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="posterize_icons"> + <item>@drawable/posterize_off</item> + <item>@drawable/posterize_on</item> + </array> + + <string-array name="redeye_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="redeye_icons"> + <item>@drawable/redeye_off</item> + <item>@drawable/redeye_on</item> + </array> + + <string-array name="rotate_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="rotate_icons"> + <item>@drawable/rotate_off</item> + <item>@drawable/rotate_on</item> + </array> + + <string-array name="saturation_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="saturation_icons"> + <item>@drawable/saturation_off</item> + <item>@drawable/saturation_on</item> + </array> + + <string-array name="sepia_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="sepia_icons"> + <item>@drawable/sepia_off</item> + <item>@drawable/sepia_on</item> + </array> + + <string-array name="shadow_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="shadow_icons"> + <item>@drawable/shadow_off</item> + <item>@drawable/shadow_on</item> + </array> + + <string-array name="sharpen_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="sharpen_icons"> + <item>@drawable/sharpen_off</item> + <item>@drawable/sharpen_on</item> + </array> + + <string-array name="softfocus_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="softfocus_icons"> + <item>@drawable/softfocus_off</item> + <item>@drawable/softfocus_on</item> + </array> + + <string-array name="straighten_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="straighten_icons"> + <item>@drawable/straighten_off</item> + <item>@drawable/straighten_on</item> + </array> + + <string-array name="temperature_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="temperature_icons"> + <item>@drawable/colortemperature_off</item> + <item>@drawable/colortemperature_on</item> + </array> + + <string-array name="tint_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="tint_icons"> + <item>@drawable/tint_off</item> + <item>@drawable/tint_on</item> + </array> + + <string-array name="vignette_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="vignette_icons"> + <item>@drawable/vignette_off</item> + <item>@drawable/vignette_on</item> + </array> + + <string-array name="warmify_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="warmify_icons"> + <item>@drawable/warmify_off</item> + <item>@drawable/warmify_on</item> + </array> + + <string-array name="undo_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="undo_icons"> + <item>@drawable/undo</item> + <item>@drawable/undo</item> + </array> + + <string-array name="redo_modes" translatable="false"> + <item>off</item> + <item>on</item> + </string-array> + + <array name="redo_icons"> + <item>@drawable/redo</item> + <item>@drawable/redo</item> + </array> + + <array name="color_picker_wheel_colors"> + <item>@color/color_picker_preset_color1</item> + <item>@color/color_picker_preset_color2</item> + <item>@color/color_picker_preset_color3</item> + <item>@color/color_picker_preset_color4</item> + <item>@color/color_picker_preset_color5</item> + <item>@color/color_picker_preset_color6</item> + <item>@color/color_picker_preset_color7</item> + <item>@color/color_picker_preset_color8</item> + <item>@color/color_picker_preset_color9</item> + <item>@color/color_picker_preset_color10</item> + <item>@color/color_picker_preset_color11</item> + <item>@color/color_picker_preset_color12</item> + <item>@color/color_picker_preset_color13</item> + <item>@color/color_picker_preset_color14</item> + <item>@color/color_picker_preset_color15</item> + <item>@color/color_picker_preset_color16</item> + <item>@color/color_picker_preset_color17</item> + <item>@color/color_picker_preset_color18</item> + <item>@color/color_picker_preset_color19</item> + <item>@color/color_picker_preset_color20</item> + <item>@color/color_picker_preset_color21</item> + <item>@color/color_picker_preset_color22</item> + <item>@color/color_picker_preset_color23</item> + <item>@color/color_picker_preset_color24</item> + </array> + +</resources> diff --git a/samples/PhotoEditor/res/values/attrs.xml b/samples/PhotoEditor/res/values/attrs.xml new file mode 100644 index 0000000..052534c --- /dev/null +++ b/samples/PhotoEditor/res/values/attrs.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<resources> + <declare-styleable name="IconIndicator"> + <attr name="icons" format="reference" /> + <attr name="modes" format="reference" /> + </declare-styleable> +</resources> diff --git a/samples/PhotoEditor/res/values/colors.xml b/samples/PhotoEditor/res/values/colors.xml new file mode 100644 index 0000000..f699c1b --- /dev/null +++ b/samples/PhotoEditor/res/values/colors.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<resources> + <color name="scale_wheel_interior_color">#40808080</color> + + <color name="color_picker_indicator_color">#ffff3377</color> + <color name="color_picker_border_color">#ffbbbbbb</color> + + <color name="color_picker_preset_color1">#ddff1e00</color> + <color name="color_picker_preset_color2">#ddff5b00</color> + <color name="color_picker_preset_color3">#ddff9900</color> + <color name="color_picker_preset_color4">#ddffd600</color> + <color name="color_picker_preset_color5">#ddeaff00</color> + <color name="color_picker_preset_color6">#ddadff00</color> + <color name="color_picker_preset_color7">#dd70ff00</color> + <color name="color_picker_preset_color8">#dd32ff00</color> + <color name="color_picker_preset_color9">#dd00ff0a</color> + <color name="color_picker_preset_color10">#dd00ff47</color> + <color name="color_picker_preset_color11">#dd00ff84</color> + <color name="color_picker_preset_color12">#dd00ffc1</color> + <color name="color_picker_preset_color13">#dd00ffff</color> + <color name="color_picker_preset_color14">#dd00c1ff</color> + <color name="color_picker_preset_color15">#dd0084ff</color> + <color name="color_picker_preset_color16">#dd0047ff</color> + <color name="color_picker_preset_color17">#dd000aff</color> + <color name="color_picker_preset_color18">#dd3300ff</color> + <color name="color_picker_preset_color19">#dd7000ff</color> + <color name="color_picker_preset_color20">#ddad00ff</color> + <color name="color_picker_preset_color21">#ddea00ff</color> + <color name="color_picker_preset_color22">#ddff00d6</color> + <color name="color_picker_preset_color23">#ddff0098</color> + <color name="color_picker_preset_color24">#ddff005b</color> +</resources> diff --git a/samples/PhotoEditor/res/values/dimen.xml b/samples/PhotoEditor/res/values/dimen.xml new file mode 100755 index 0000000..cbadea0 --- /dev/null +++ b/samples/PhotoEditor/res/values/dimen.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <dimen name="group_cotent_padding_top">10dp</dimen> + <dimen name="group_cotent_padding_bottom">15dp</dimen> + <dimen name="group_header_height">48dp</dimen> + <dimen name="group_header_padding_bottom">10dp</dimen> + <dimen name="group_header_padding_left">11dp</dimen> + <dimen name="group_header_padding_right">5dp</dimen> + <dimen name="group_arrow_size">20dp</dimen> + <dimen name="group_label_text_size">15sp</dimen> + <dimen name="effect_label_text_size">14sp</dimen> + <dimen name="effect_icon_size">92dp</dimen> + <dimen name="effect_padding_top">10dp</dimen> + <dimen name="effect_padding_bottom">15dp</dimen> + <dimen name="effects_bar_width">124dp</dimen> + <dimen name="effects_bar_margin_top">4dp</dimen> + <dimen name="effects_bar_margin_bottom">4dp</dimen> + <dimen name="action_bar_height">50dp</dimen> + <dimen name="action_bar_text_size">18sp</dimen> + <dimen name="action_bar_arrow_padding_top">17dp</dimen> + <dimen name="action_bar_arrow_padding_bottom">17dp</dimen> + <dimen name="action_bar_arrow_padding_left">3dp</dimen> + <dimen name="action_bar_arrow_padding_right">0dp</dimen> + <dimen name="action_bar_icon_padding_top">5dp</dimen> + <dimen name="action_bar_icon_padding_bottom">5dp</dimen> + <dimen name="action_bar_icon_padding_left">0dp</dimen> + <dimen name="action_bar_icon_padding_right">8dp</dimen> + <dimen name="action_button_padding_top">7dp</dimen> + <dimen name="action_button_padding_bottom">7dp</dimen> + <dimen name="action_button_padding_left">22dp</dimen> + <dimen name="action_button_padding_right">22dp</dimen> + <dimen name="action_button_padding_right_most">45dp</dimen> + <dimen name="wheel_layout_marginLeft">-48dp</dimen> + <dimen name="wheel_layout_size">240dp</dimen> + <dimen name="wheel_thumb_size">51dp</dimen> + <dimen name="crop_indicator_size">32dp</dimen> +</resources> diff --git a/samples/PhotoEditor/res/values/strings.xml b/samples/PhotoEditor/res/values/strings.xml new file mode 100644 index 0000000..c4f587c --- /dev/null +++ b/samples/PhotoEditor/res/values/strings.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Application name appearing in the application launcher. [CHAR LIMIT=NONE] --> + <string name="app_name">Photo Studio</string> + + <!-- Toast shown when selected photo could not be loaded. [CHAR LIMIT=50] --> + <string name="loading_failure">Cannot load the photo for editing</string> + + <!-- Toast shown when edited photo could not be saved. [CHAR LIMIT=50] --> + <string name="saving_failure">A problem occurred during saving</string> + + <!-- Toast shown when edited photo is successfully saved with filename %s [CHAR LIMIT=50] --> + <string name="photo_saved"><xliff:g id="filename">%s</xliff:g> saved</string> + + <!-- Dialog message prompted when the user is abandoning unsaved changes. [CHAR LIMIT=50] --> + <string name="save_photo">Save edited photo?</string> + + <!-- Dialog yes button for the user to accept text presented in a dialog. [CHAR LIMIT=12] --> + <string name="yes">Yes</string> + + <!-- Dialog no button for the user to decline text presented in a dialog. [CHAR LIMIT=12] --> + <string name="no">No</string> + + <!-- Dialog cancel button for the user to cancel a dialog. [CHAR LIMIT=12] --> + <string name="cancel">Cancel</string> + + <!-- Directory name where edited photo will be saved in the storage. [CHAR LIMIT=12] --> + <string name="edited_photo_bucket_name">Edited</string> + + <!-- Menu label to group all artistic-related photo effects, e.g. vignette, posterize, etc. + [CHAR LIMIT=11] --> + <string name="artistic_group">Artistic</string> + + <!-- Menu label to group all color-related photo effects, e.g. color-temperature, tint, etc. + [CHAR LIMIT=11] --> + <string name="color_group">Color</string> + + <!-- Menu label to group all exposure-related photo effects, e.g. fill-light, highlight, etc. + [CHAR LIMIT=11] --> + <string name="exposure_group">Exposure</string> + + <!-- Menu label to group all fix-related photo effects, e.g. straighten, red-eye removal, etc. + [CHAR LIMIT=11] --> + <string name="fix_group">Fix</string> + + <!-- Name for the photo effect 'Feel Lucky' that auto-fixes exposure. [CHAR LIMIT=15] --> + <string name="autofix">Feel Lucky</string> + + <!-- Name for the photo effect that crops photo. [CHAR LIMIT=15] --> + <string name="crop">Crop</string> + + <!-- Name for the photo effect that applies cross-process effect. [CHAR LIMIT=15] --> + <string name="crossprocess">Cross-process</string> + + <!-- Name for the photo effect that applies black/white documentary styles. [CHAR LIMIT=15] --> + <string name="documentary">Documentary</string> + + <!-- Name for the photo effect that doodles on photo. [CHAR LIMIT=15] --> + <string name="doodle">Doodle</string> + + <!-- Name for the photo effect that makes photo only two color tones. [CHAR LIMIT=15] --> + <string name="duotone">Duo-tone</string> + + <!-- Name for the photo effect that fills back-light. [CHAR LIMIT=15] --> + <string name="filllight">Fill Light</string> + + <!-- Name for the photo effect that applies fisheye lens distortion. [CHAR LIMIT=15] --> + <string name="fisheye">Fisheye</string> + + <!-- Name for the photo effect that flips photo vertically or horizontally. [CHAR LIMIT=15] --> + <string name="flip">Flip</string> + + <!-- Name for the photo effect that adds grains and noises. [CHAR LIMIT=15] --> + <string name="grain">Film Grain</string> + + <!-- Name for the photo effect that converts colors to grayscales. [CHAR LIMIT=15] --> + <string name="grayscale">Grayscale</string> + + <!-- Name for the photo effect that adds highlights. [CHAR LIMIT=15] --> + <string name="highlight">Highlights</string> + + <!-- Name for the photo effect that applies lomo-camera styles. [CHAR LIMIT=15] --> + <string name="lomoish">Lomo-ish</string> + + <!-- Name for the photo effect that inverts photo to negative images. [CHAR LIMIT=15] --> + <string name="negative">Negative</string> + + <!-- Name for the photo effect that applies posterization. [CHAR LIMIT=15] --> + <string name="posterize">Posterize</string> + + <!-- Name for the photo effect that remove red eyes. [CHAR LIMIT=15] --> + <string name="redeye">Red Eye</string> + + <!-- Name for the photo effect that rotates photo. [CHAR LIMIT=15] --> + <string name="rotate">Rotate</string> + + <!-- Name for the photo effect that adjusts color saturation. [CHAR LIMIT=15] --> + <string name="saturation">Saturation</string> + + <!-- Name for the photo effect that applies sepia color toning. [CHAR LIMIT=15] --> + <string name="sepia">Sepia</string> + + <!-- Name for the photo effect that adds shadows. [CHAR LIMIT=15] --> + <string name="shadow">Shadows</string> + + <!-- Name for the photo effect that sharpens blurred photo. [CHAR LIMIT=15] --> + <string name="sharpen">Sharpen</string> + + <!-- Name for the photo effect that applies soft-focus. [CHAR LIMIT=15] --> + <string name="softfocus">Soft Focus</string> + + <!-- Name for the photo effect that straightens crooked photo. [CHAR LIMIT=15] --> + <string name="straighten">Straighten</string> + + <!-- Name for the photo effect that adjusts color-temperature. [CHAR LIMIT=15] --> + <string name="temperature">Temperature</string> + + <!-- Name for the photo effect that tints photo with various colors. [CHAR LIMIT=15] --> + <string name="tint">Tint</string> + + <!-- Name for the photo effect that fades off photo edges. [CHAR LIMIT=15] --> + <string name="vignette">Vignette</string> + + <!-- Name for the photo effect that applies warmify color toning. [CHAR LIMIT=15] --> + <string name="warmify">Warmify</string> + + <!-- Tool-tip toast shown when the user chooses to crop photo. [CHAR LIMIT=50] --> + <string name="crop_tooltip">Drag photo to crop it</string> + + <!-- Tool-tip toast shown when the user chooses to doodle on photo. [CHAR LIMIT=50] --> + <string name="doodle_tooltip">Draw on photo to doodle</string> + + <!-- Tool-tip toast shown when the user chooses to flip photo. [CHAR LIMIT=50] --> + <string name="flip_tooltip">Drag photo to flip it</string> + + <!-- Tool-tip toast shown when the user chooses to remove red eyes. [CHAR LIMIT=50] --> + <string name="redeye_tooltip">Tap to remove red eyes</string> + + <!-- Tool-tip toast shown when the user chooses to rotate photo. [CHAR LIMIT=50] --> + <string name="rotate_tooltip">Drag photo to rotate it</string> + + <!-- Tool-tip toast shown when the user chooses to straighten photo. [CHAR LIMIT=50] --> + <string name="straighten_tooltip">Drag photo to straighten it</string> +</resources> diff --git a/samples/PhotoEditor/res/values/styles.xml b/samples/PhotoEditor/res/values/styles.xml new file mode 100644 index 0000000..35bca10 --- /dev/null +++ b/samples/PhotoEditor/res/values/styles.xml @@ -0,0 +1,166 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="GroupHeader"> + <item name="android:layout_width">fill_parent</item> + <item name="android:layout_height">@dimen/group_header_height</item> + <item name="android:paddingBottom">@dimen/group_header_padding_bottom</item> + <item name="android:paddingLeft">@dimen/group_header_padding_left</item> + <item name="android:paddingRight">@dimen/group_header_padding_right</item> + <item name="android:background">@drawable/group_header</item> + </style> + <style name="GroupArrow"> + <item name="android:layout_width">@dimen/group_arrow_size</item> + <item name="android:layout_height">@dimen/group_arrow_size</item> + <item name="android:layout_gravity">center_vertical|right</item> + <item name="android:paddingTop">2dp</item> + <item name="android:scaleType">fitCenter</item> + <item name="android:src">@drawable/arrow_down</item> + </style> + <style name="GroupLabel"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_gravity">center_vertical</item> + <item name="android:gravity">center_vertical</item> + <item name="android:textSize">@dimen/group_label_text_size</item> + <item name="android:textColor">#FFFFFF</item> + <item name="android:shadowColor">#000000</item> + <item name="android:shadowRadius">2.0</item> + </style> + <style name="GroupContent" parent="@style/EffectsBarLinearLayout"> + <item name="android:paddingTop">@dimen/group_cotent_padding_top</item> + <item name="android:paddingBottom">@dimen/group_cotent_padding_bottom</item> + </style> + <style name="EffectIcon"> + <item name="android:layout_width">@dimen/effect_icon_size</item> + <item name="android:layout_height">@dimen/effect_icon_size</item> + <item name="android:layout_gravity">center_horizontal</item> + <item name="android:scaleType">fitCenter</item> + </style> + <style name="EffectLabel"> + <item name="android:layout_width">fill_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_gravity">center_horizontal</item> + <item name="android:gravity">center</item> + <item name="android:textSize">@dimen/effect_label_text_size</item> + <item name="android:textColor">#FFFFFF</item> + <item name="android:shadowColor">#000000</item> + <item name="android:shadowRadius">2.0</item> + </style> + <style name="Effect"> + <item name="android:layout_width">fill_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_gravity">center_horizontal</item> + <item name="android:paddingTop">@dimen/effect_padding_top</item> + <item name="android:paddingBottom">@dimen/effect_padding_bottom</item> + <item name="android:orientation">vertical</item> + </style> + <style name="EffectsBarLinearLayout"> + <item name="android:layout_width">fill_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:orientation">vertical</item> + </style> + <style name="EffectsBar"> + <item name="android:layout_width">@dimen/effects_bar_width</item> + <item name="android:layout_height">fill_parent</item> + <item name="android:layout_alignParentRight">true</item> + <item name="android:layout_marginTop">@dimen/effects_bar_margin_top</item> + <item name="android:layout_marginBottom">@dimen/effects_bar_margin_bottom</item> + <item name="android:scrollbars">none</item> + </style> + <style name="ActionBar"> + <item name="android:layout_alignParentTop">true</item> + <item name="android:layout_width">fill_parent</item> + <item name="android:layout_height">@dimen/action_bar_height</item> + <item name="android:background">@null</item> + </style> + <style name="ActionBarTranslucent"> + <item name="android:layout_width">fill_parent</item> + <item name="android:layout_height">fill_parent</item> + <item name="android:background">@drawable/actionbar_translucent</item> + </style> + <style name="ActionBarLinearLayout"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">fill_parent</item> + <item name="android:layout_centerVertical">true</item> + <item name="android:orientation">horizontal</item> + </style> + <style name="ActionBarBackLinearLayout" parent="@style/ActionBarLinearLayout"> + <item name="android:clickable">true</item> + <item name="android:focusable">true</item> + <item name="android:background">?android:attr/selectableItemBackground</item> + </style> + <style name="ActionBarImageView"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">fill_parent</item> + <item name="android:layout_gravity">center</item> + <item name="android:scaleType">centerInside</item> + <item name="android:adjustViewBounds">true</item> + </style> + <style name="ActionBarArrow" parent="@style/ActionBarImageView"> + <item name="android:paddingTop">@dimen/action_bar_arrow_padding_top</item> + <item name="android:paddingBottom">@dimen/action_bar_arrow_padding_bottom</item> + <item name="android:paddingLeft">@dimen/action_bar_arrow_padding_left</item> + <item name="android:paddingRight">@dimen/action_bar_arrow_padding_right</item> + <item name="android:src">@drawable/arrow_back</item> + </style> + <style name="ActionBarIcon" parent="@style/ActionBarImageView"> + <item name="android:paddingTop">@dimen/action_bar_icon_padding_top</item> + <item name="android:paddingBottom">@dimen/action_bar_icon_padding_bottom</item> + <item name="android:paddingLeft">@dimen/action_bar_icon_padding_left</item> + <item name="android:paddingRight">@dimen/action_bar_icon_padding_right</item> + <item name="android:src">@drawable/icon</item> + </style> + <style name="ActionBarText"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_gravity">center</item> + <item name="android:textSize">@dimen/action_bar_text_size</item> + <item name="android:textColor">#FFFFFF</item> + </style> + <style name="ActionButton" parent="@style/ActionBarImageView"> + <item name="android:paddingTop">@dimen/action_button_padding_top</item> + <item name="android:paddingBottom">@dimen/action_button_padding_bottom</item> + <item name="android:paddingLeft">@dimen/action_button_padding_left</item> + <item name="android:paddingRight">@dimen/action_button_padding_right</item> + <item name="android:background">?android:attr/selectableItemBackground</item> + </style> + <style name="RightmostActionButton" parent="@style/ActionButton"> + <item name="android:paddingRight">@dimen/action_button_padding_right_most</item> + </style> + <style name="Wheel"> + <item name="android:layout_width">@dimen/wheel_layout_size</item> + <item name="android:layout_height">@dimen/wheel_layout_size</item> + <item name="android:layout_alignParentLeft">true</item> + <item name="android:layout_marginLeft">@dimen/wheel_layout_marginLeft</item> + <item name="android:background">@null</item> + <item name="android:visibility">invisible</item> + </style> + <style name="FullscreenToolView"> + <item name="android:layout_width">fill_parent</item> + <item name="android:layout_height">fill_parent</item> + <item name="android:visibility">invisible</item> + </style> + <style name="SpinnerProgressDialog"> + <item name="android:background">@android:color/transparent</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowFrame">@null</item> + <item name="android:windowTitleStyle">@null</item> + <item name="android:windowIsFloating">true</item> + <item name="android:backgroundDimEnabled">false</item> + </style> +</resources> diff --git a/samples/PhotoEditor/src/com/android/photoeditor/ActionBar.java b/samples/PhotoEditor/src/com/android/photoeditor/ActionBar.java new file mode 100644 index 0000000..4465741 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/ActionBar.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ViewSwitcher; + +/** + * Action bar that contains buttons such as undo, redo, save, etc. and listens to stack changes for + * enabling/disabling buttons. + */ +public class ActionBar extends ViewSwitcher implements FilterStack.StackListener { + + /** + * Listener of action button clicked. + */ + public interface ActionBarListener { + + void onQuickview(boolean on); + + void onUndo(); + + void onRedo(); + + void onSave(); + } + + private static final int ENABLE_BUTTON = 1; + private static final int ENABLED_ALPHA = 255; + private static final int DISABLED_ALPHA = 120; + + private final Handler handler; + private ImageButton save; + private ImageButton undo; + private ImageButton redo; + private ImageButton quickview; + + public ActionBar(Context context, AttributeSet attrs) { + super(context, attrs); + + handler = new Handler() { + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case ENABLE_BUTTON: + boolean canUndo = (msg.arg1 > 0); + boolean canRedo = (msg.arg2 > 0); + enableButton(quickview, canUndo); + enableButton(save, canUndo); + enableButton(undo, canUndo); + enableButton(redo, canRedo); + break; + } + } + }; + } + + /** + * Initializes with a non-null ActionBarListener. + */ + public void initialize(final ActionBarListener listener) { + save = (ImageButton) findViewById(R.id.save_button); + save.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (isEnabled()) { + listener.onSave(); + } + } + }); + + undo = (ImageButton) findViewById(R.id.undo_button); + undo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (isEnabled()) { + listener.onUndo(); + } + } + }); + + redo = (ImageButton) findViewById(R.id.redo_button); + redo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (isEnabled()) { + listener.onRedo(); + } + } + }); + + quickview = (ImageButton) findViewById(R.id.quickview_button); + quickview.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (isEnabled()) { + ActionBar.this.showNext(); + listener.onQuickview(true); + } + } + }); + + View quickviewOn = findViewById(R.id.quickview_on_button); + quickviewOn.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (isEnabled()) { + ActionBar.this.showNext(); + listener.onQuickview(false); + } + } + }); + + resetButtons(); + } + + public void resetButtons() { + // Disable buttons immediately instead of waiting for ENABLE_BUTTON messages which may + // happen some time later after stack changes. + enableButton(save, false); + enableButton(undo, false); + enableButton(redo, false); + enableButton(quickview, false); + } + + public void disableSave() { + enableButton(save, false); + } + + private void enableButton(ImageButton button, boolean enabled) { + button.setEnabled(enabled); + button.setAlpha(enabled ? ENABLED_ALPHA : DISABLED_ALPHA); + } + + @Override + public void onStackChanged(boolean canUndo, boolean canRedo) { + // Listens to stack changes that may come from the worker thread; send messages to enable + // buttons only in the UI thread. + handler.sendMessage(handler.obtainMessage(ENABLE_BUTTON, canUndo ? 1 : 0, canRedo ? 1 : 0)); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/BitmapUtils.java b/samples/PhotoEditor/src/com/android/photoeditor/BitmapUtils.java new file mode 100644 index 0000000..8678f10 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/BitmapUtils.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.net.Uri; +import android.provider.MediaStore.Images.ImageColumns; +import android.util.Log; + +import java.io.Closeable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Utils for bitmap operations. + */ +public class BitmapUtils { + + private static final String TAG = "BitmapUtils"; + private static final int DEFAULT_COMPRESS_QUALITY = 90; + private static final int INDEX_ORIENTATION = 0; + + private static final String[] IMAGE_PROJECTION = new String[] { + ImageColumns.ORIENTATION + }; + + private final Context context; + + public BitmapUtils(Context context) { + this.context = context; + } + + /** + * Returns an immutable bitmap from subset of source bitmap transformed by the given matrix. + */ + public static Bitmap createBitmap(Bitmap bitmap, Matrix m) { + // TODO: Re-implement createBitmap to avoid ARGB -> RBG565 conversion on platforms + // prior to honeycomb. + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true); + } + + private void closeStream(Closeable stream) { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private Rect getBitmapBounds(Uri uri) { + Rect bounds = new Rect(); + InputStream is = null; + + try { + is = context.getContentResolver().openInputStream(uri); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(is, null, options); + + bounds.right = options.outWidth; + bounds.bottom = options.outHeight; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + closeStream(is); + } + + return bounds; + } + + private int getOrientation(Uri uri) { + int orientation = 0; + Cursor cursor = context.getContentResolver().query(uri, IMAGE_PROJECTION, null, null, null); + if ((cursor != null) && cursor.moveToNext()) { + orientation = cursor.getInt(INDEX_ORIENTATION); + } + return orientation; + } + + /** + * Decodes immutable bitmap that keeps aspect-ratio and spans most within the given rectangle. + */ + private Bitmap decodeBitmap(Uri uri, int width, int height) { + InputStream is = null; + Bitmap bitmap = null; + + try { + // TODO: Take max pixels allowed into account for calculation to avoid possible OOM. + Rect bounds = getBitmapBounds(uri); + int sampleSize = Math.max(bounds.width() / width, bounds.height() / height); + sampleSize = Math.min(sampleSize, + Math.max(bounds.width() / height, bounds.height() / width)); + + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = Math.max(sampleSize, 1); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + + is = context.getContentResolver().openInputStream(uri); + bitmap = BitmapFactory.decodeStream(is, null, options); + } catch (FileNotFoundException e) { + Log.e(TAG, "FileNotFoundException: " + uri); + } finally { + closeStream(is); + } + + // Scale down the sampled bitmap if it's still larger than the desired dimension. + if (bitmap != null) { + float scale = Math.min((float) width / bitmap.getWidth(), + (float) height / bitmap.getHeight()); + scale = Math.max(scale, Math.min((float) height / bitmap.getWidth(), + (float) width / bitmap.getHeight())); + if (scale < 1) { + Matrix m = new Matrix(); + m.setScale(scale, scale); + Bitmap transformed = createBitmap(bitmap, m); + bitmap.recycle(); + return transformed; + } + } + return bitmap; + } + + /** + * Gets decoded bitmap that keeps orientation as well. + */ + public Bitmap getBitmap(Uri uri, int width, int height) { + Bitmap bitmap = decodeBitmap(uri, width, height); + + // Rotate the decoded bitmap according to its orientation if it's necessary. + if (bitmap != null) { + int orientation = getOrientation(uri); + if (orientation != 0) { + Matrix m = new Matrix(); + m.setRotate(orientation); + Bitmap transformed = createBitmap(bitmap, m); + bitmap.recycle(); + return transformed; + } + } + return bitmap; + } + + /** + * Saves the bitmap by given directory, filename, and format; if the directory is given null, + * then saves it under the cache directory. + */ + public File saveBitmap( + Bitmap bitmap, String directory, String filename, CompressFormat format) { + + if (directory == null) { + directory = context.getCacheDir().getAbsolutePath(); + } else { + // Check if the given directory exists or try to create it. + File file = new File(directory); + if (!file.isDirectory() && !file.mkdirs()) { + return null; + } + } + + File file = null; + OutputStream os = null; + + try { + filename = (format == CompressFormat.PNG) ? filename + ".png" : filename + ".jpg"; + file = new File(directory, filename); + os = new FileOutputStream(file); + bitmap.compress(format, DEFAULT_COMPRESS_QUALITY, os); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + closeStream(os); + } + return file; + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/EffectsBar.java b/samples/PhotoEditor/src/com/android/photoeditor/EffectsBar.java new file mode 100644 index 0000000..63cbf3f --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/EffectsBar.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; +import android.widget.TextView; + +import com.android.photoeditor.actions.AutoFixAction; +import com.android.photoeditor.actions.ColorTemperatureAction; +import com.android.photoeditor.actions.CropAction; +import com.android.photoeditor.actions.CrossProcessAction; +import com.android.photoeditor.actions.DocumentaryAction; +import com.android.photoeditor.actions.DoodleAction; +import com.android.photoeditor.actions.DuotoneAction; +import com.android.photoeditor.actions.FillLightAction; +import com.android.photoeditor.actions.FilterAction; +import com.android.photoeditor.actions.FisheyeAction; +import com.android.photoeditor.actions.FlipAction; +import com.android.photoeditor.actions.GrainAction; +import com.android.photoeditor.actions.GrayscaleAction; +import com.android.photoeditor.actions.HighlightAction; +import com.android.photoeditor.actions.LomoishAction; +import com.android.photoeditor.actions.NegativeAction; +import com.android.photoeditor.actions.PosterizeAction; +import com.android.photoeditor.actions.RedEyeAction; +import com.android.photoeditor.actions.RotateAction; +import com.android.photoeditor.actions.SaturationAction; +import com.android.photoeditor.actions.SepiaAction; +import com.android.photoeditor.actions.ShadowAction; +import com.android.photoeditor.actions.SharpenAction; +import com.android.photoeditor.actions.StraightenAction; +import com.android.photoeditor.actions.TintAction; +import com.android.photoeditor.actions.VignetteAction; +import com.android.photoeditor.actions.WarmifyAction; + +import java.util.ArrayList; +import java.util.List; + +/** + * Scroll view that contains all effects for editing photo by mapping each effect to trigger one + * corresponding FilterAction. + */ +public class EffectsBar extends ScrollView { + + private final List<Effect> effects = new ArrayList<Effect>(); + private TextView effectName; + + public EffectsBar(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void initialize(FilterStack filterStack, PhotoView photoView, ViewGroup tools) { + effects.add(new Effect(R.id.autofix_effect, + new AutoFixAction(filterStack, tools))); + + effects.add(new Effect(R.id.crop_effect, + new CropAction(filterStack, tools))); + + effects.add(new Effect(R.id.crossprocess_effect, + new CrossProcessAction(filterStack, tools))); + + effects.add(new Effect(R.id.documentary_effect, + new DocumentaryAction(filterStack, tools))); + + effects.add(new Effect(R.id.doodle_effect, + new DoodleAction(filterStack, tools))); + + effects.add(new Effect(R.id.duotone_effect, + new DuotoneAction(filterStack, tools))); + + effects.add(new Effect(R.id.filllight_effect, + new FillLightAction(filterStack, tools))); + + effects.add(new Effect(R.id.fisheye_effect, + new FisheyeAction(filterStack, tools))); + + effects.add(new Effect(R.id.flip_effect, + new FlipAction(filterStack, tools))); + + effects.add(new Effect(R.id.grain_effect, + new GrainAction(filterStack, tools))); + + effects.add(new Effect(R.id.grayscale_effect, + new GrayscaleAction(filterStack, tools))); + + effects.add(new Effect(R.id.highlight_effect, + new HighlightAction(filterStack, tools))); + + effects.add(new Effect(R.id.lomoish_effect, + new LomoishAction(filterStack, tools))); + + effects.add(new Effect(R.id.negative_effect, + new NegativeAction(filterStack, tools))); + + effects.add(new Effect(R.id.posterize_effect, + new PosterizeAction(filterStack, tools))); + + effects.add(new Effect(R.id.redeye_effect, + new RedEyeAction(filterStack, tools))); + + effects.add(new Effect(R.id.rotate_effect, + new RotateAction(filterStack, tools))); + + effects.add(new Effect(R.id.saturation_effect, + new SaturationAction(filterStack, tools))); + + effects.add(new Effect(R.id.sepia_effect, + new SepiaAction(filterStack, tools))); + + effects.add(new Effect(R.id.shadow_effect, + new ShadowAction(filterStack, tools))); + + effects.add(new Effect(R.id.sharpen_effect, + new SharpenAction(filterStack, tools))); + + effects.add(new Effect(R.id.straighten_effect, + new StraightenAction(filterStack, tools))); + + effects.add(new Effect(R.id.temperature_effect, + new ColorTemperatureAction(filterStack, tools))); + + effects.add(new Effect(R.id.tint_effect, + new TintAction(filterStack, tools))); + + effects.add(new Effect(R.id.vignette_effect, + new VignetteAction(filterStack, tools))); + + effects.add(new Effect(R.id.warmify_effect, + new WarmifyAction(filterStack, tools))); + + effectName = (TextView) tools.findViewById(R.id.action_effect_name); + + // Disable hardware acceleration on this view to make alpha animations work for idle fading. + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + + setEnabled(false); + } + + public void effectsOff(Runnable runnableOnEffectsOff) { + for (Effect effect : effects) { + if (effect.on) { + effect.turnOff(runnableOnEffectsOff); + return; + } + } + // Just execute the runnable right away if all effects are already off. + if (runnableOnEffectsOff != null) { + runnableOnEffectsOff.run(); + } + } + + public boolean hasEffectOn() { + for (Effect effect : effects) { + if (effect.on) { + return true; + } + } + return false; + } + + private class Effect implements FilterAction.FilterActionListener { + + private final FilterAction action; + private final CharSequence name; + private final IconIndicator button; + private boolean on; + private Runnable runnableOnODone; + + public Effect(int effectId, FilterAction action) { + this.action = action; + + View view = findViewById(effectId); + name = ((TextView) view.findViewById(R.id.effect_label)).getText(); + button = (IconIndicator) view.findViewById(R.id.effect_button); + button.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + if (isEnabled()) { + if (on) { + turnOff(null); + } else { + // Have other effects done turning off first and then turn on itself. + effectsOff(new Runnable() { + + @Override + public void run() { + turnOn(); + } + }); + } + } + } + }); + } + + private void turnOn() { + effectName.setText(name); + button.setMode("on"); + on = true; + action.begin(this); + } + + private void turnOff(Runnable runnableOnODone) { + this.runnableOnODone = runnableOnODone; + action.end(); + } + + @Override + public void onDone() { + if (on) { + effectName.setText(""); + button.setMode("off"); + on = false; + + if (runnableOnODone != null) { + runnableOnODone.run(); + runnableOnODone = null; + } + } + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/EffectsGroup.java b/samples/PhotoEditor/src/com/android/photoeditor/EffectsGroup.java new file mode 100644 index 0000000..7c1f9af --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/EffectsGroup.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import java.util.ArrayList; +import java.util.List; + +/** + * Groups effects in an accordion menu style that could either expand or fold effects. + */ +public class EffectsGroup extends LinearLayout { + + private static final int ANIMATION_INTERVAL = 75; + + private final Drawable downArrow; + private final Drawable rightArrow; + + private boolean expandEffects; + + public EffectsGroup(Context context, AttributeSet attrs) { + super(context, attrs); + + downArrow = context.getResources().getDrawable(R.drawable.arrow_down); + rightArrow = context.getResources().getDrawable(R.drawable.arrow_right); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + if (expandEffects) { + requestRectangleOnScreen(new Rect(0, 0, 0, getHeight())); + } + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + final ImageView arrow = (ImageView) findViewById(R.id.group_arrow); + final ViewGroup container = (ViewGroup) findViewById(R.id.grouped_effects); + final List<View> effects = new ArrayList<View>(); + for (int i = 0; i < container.getChildCount(); i++) { + effects.add(container.getChildAt(i)); + } + + findViewById(R.id.group_header).setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + if (container.getVisibility() == VISIBLE) { + expandEffects = false; + + int delay = 0; + for (int i = effects.size() - 1; i >= 0; i--) { + final View effect = effects.get(i); + + postDelayed(new Runnable() { + + @Override + public void run() { + effect.setVisibility(GONE); + } + }, delay); + delay += ANIMATION_INTERVAL; + } + + postDelayed(new Runnable() { + + @Override + public void run() { + container.setVisibility(GONE); + arrow.setImageDrawable(rightArrow); + } + }, delay - ANIMATION_INTERVAL); + } else { + expandEffects = true; + + arrow.setImageDrawable(downArrow); + container.setVisibility(VISIBLE); + + int delay = 0; + for (int i = 0; i < effects.size(); i++) { + final View effect = effects.get(i); + + postDelayed(new Runnable() { + + @Override + public void run() { + effect.setVisibility(VISIBLE); + } + }, delay); + delay += ANIMATION_INTERVAL; + } + } + } + }); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/FilterStack.java b/samples/PhotoEditor/src/com/android/photoeditor/FilterStack.java new file mode 100644 index 0000000..9a9b8d7 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/FilterStack.java @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; + +import com.android.photoeditor.filters.Filter; + +import java.util.Stack; +import java.util.Vector; + +/** + * A stack of filters to be applied onto a photo. + */ +public class FilterStack { + + /** + * Listener of stack changes. + */ + public interface StackListener { + + void onStackChanged(boolean canUndo, boolean canRedo); + } + + private static class OutputMessageObj { + PhotoOutputCallback callback; + Photo result; + } + + private static final int COPY_SOURCE = 1; + private static final int COPY_RESULT = 2; + private static final int SET_SOURCE = 3; + private static final int CLEAR_SOURCE = 4; + private static final int CLEAR_STACKS = 5; + private static final int PUSH_FILTER = 6; + private static final int UNDO = 7; + private static final int REDO = 8; + private static final int TOP_FILTER_CHANGE = 9; + private static final int OUTPUT = 10; + + private final Stack<Filter> appliedStack = new Stack<Filter>(); + private final Stack<Filter> redoStack = new Stack<Filter>(); + private final Vector<Message> pendingMessages = new Vector<Message>(); + private final Handler mainHandler; + private final Handler workerHandler; + + // Use two photo buffers as in and out in turns to apply filters in the stack. + private final Photo[] buffers = new Photo[2]; + + private Photo source; + private StackListener stackListener; + + public FilterStack() { + HandlerThread workerThread = new HandlerThread("FilterStackWorker"); + workerThread.start(); + + mainHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case OUTPUT: + OutputMessageObj obj = (OutputMessageObj) msg.obj; + obj.callback.onReady(obj.result); + break; + } + } + }; + workerHandler = new Handler(workerThread.getLooper()) { + + private void output(PhotoOutputCallback callback, Photo target) { + // Copy target photo in rgb-565 format to update photo-view or save. + OutputMessageObj obj = new OutputMessageObj(); + obj.callback = callback; + obj.result = (target != null) ? target.copy(Bitmap.Config.RGB_565) : null; + mainHandler.sendMessage(mainHandler.obtainMessage(OUTPUT, obj)); + } + + private void clearBuffers() { + pendingMessages.clear(); + workerHandler.removeMessages(TOP_FILTER_CHANGE); + mainHandler.removeMessages(OUTPUT); + for (int i = 0; i < buffers.length; i++) { + if (buffers[i] != null) { + buffers[i].clear(); + buffers[i] = null; + } + } + } + + private void reallocateBuffer(int target) { + int other = target ^ 1; + buffers[target] = Photo.create(Bitmap.createBitmap( + buffers[other].width(), buffers[other].height(), Bitmap.Config.ARGB_8888)); + } + + private void invalidate() { + // In/out buffers need redrawn by reloading source photo and re-applying filters. + clearBuffers(); + buffers[0] = (source != null) ? source.copy(Bitmap.Config.ARGB_8888) : null; + if (buffers[0] != null) { + reallocateBuffer(1); + + int out = 1; + for (Filter filter : appliedStack) { + runFilter(filter, out); + out = out ^ 1; + } + } + } + + private void runFilter(Filter filter, int out) { + if ((buffers[0] != null) && (buffers[1] != null)) { + int in = out ^ 1; + filter.process(buffers[in], buffers[out]); + if (!buffers[in].matchDimension(buffers[out])) { + buffers[in].clear(); + reallocateBuffer(in); + } + } + } + + private int getOutBufferIndex() { + // buffers[0] and buffers[1] are swapped in turns as the in/out buffers for + // processing stacked filters. For example, the first filter reads buffer[0] and + // writes buffer[1]; the second filter then reads buffer[1] and writes buffer[0]. + return appliedStack.size() % 2; + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case COPY_SOURCE: + output((PhotoOutputCallback) msg.obj, source); + break; + + case COPY_RESULT: + output((PhotoOutputCallback) msg.obj, buffers[getOutBufferIndex()]); + break; + + case SET_SOURCE: + source = (Photo) msg.obj; + invalidate(); + break; + + case CLEAR_SOURCE: + if (source != null) { + source.clear(); + source = null; + } + clearBuffers(); + break; + + case CLEAR_STACKS: + redoStack.clear(); + appliedStack.clear(); + break; + + case PUSH_FILTER: + redoStack.clear(); + appliedStack.push((Filter) msg.obj); + stackChanged(); + break; + + case UNDO: + if (!appliedStack.empty()) { + redoStack.push(appliedStack.pop()); + stackChanged(); + invalidate(); + } + output((PhotoOutputCallback) msg.obj, buffers[getOutBufferIndex()]); + break; + + case REDO: + if (!redoStack.empty()) { + Filter filter = redoStack.pop(); + appliedStack.push(filter); + stackChanged(); + runFilter(filter, getOutBufferIndex()); + } + output((PhotoOutputCallback) msg.obj, buffers[getOutBufferIndex()]); + break; + + case TOP_FILTER_CHANGE: + if (pendingMessages.remove(msg) && !appliedStack.empty()) { + int out = getOutBufferIndex(); + runFilter(appliedStack.peek(), out); + output((PhotoOutputCallback) msg.obj, buffers[out]); + } + break; + } + } + }; + } + + public void getSourceCopy(PhotoOutputCallback callback) { + workerHandler.sendMessage(workerHandler.obtainMessage(COPY_SOURCE, callback)); + } + + public void getResultCopy(PhotoOutputCallback callback) { + workerHandler.sendMessage(workerHandler.obtainMessage(COPY_RESULT, callback)); + } + + public void setPhotoSource(Photo source) { + workerHandler.sendMessage(workerHandler.obtainMessage(SET_SOURCE, source)); + } + + public void clearPhotoSource() { + workerHandler.sendMessage(workerHandler.obtainMessage(CLEAR_SOURCE)); + } + + public void clearStacks() { + workerHandler.sendMessage(workerHandler.obtainMessage(CLEAR_STACKS)); + } + + public void pushFilter(Filter filter) { + workerHandler.sendMessage(workerHandler.obtainMessage(PUSH_FILTER, filter)); + } + + public void undo(PhotoOutputCallback callback) { + workerHandler.sendMessage(workerHandler.obtainMessage(UNDO, callback)); + } + + public void redo(PhotoOutputCallback callback) { + workerHandler.sendMessage(workerHandler.obtainMessage(REDO, callback)); + } + + public void topFilterChanged(PhotoOutputCallback callback) { + // Flush outdated top-filter messages before sending new ones. + Message msg = workerHandler.obtainMessage(TOP_FILTER_CHANGE, callback); + pendingMessages.clear(); + pendingMessages.add(msg); + workerHandler.removeMessages(TOP_FILTER_CHANGE); + workerHandler.sendMessage(msg); + } + + public synchronized void setStackListener(StackListener listener) { + stackListener = listener; + } + + private synchronized void stackChanged() { + if (stackListener != null) { + stackListener.onStackChanged(!appliedStack.empty(), !redoStack.empty()); + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/IconIndicator.java b/samples/PhotoEditor/src/com/android/photoeditor/IconIndicator.java new file mode 100644 index 0000000..173e88e --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/IconIndicator.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.widget.ImageView; + +/** + * Represents image icons/buttons having various modes. + */ +public class IconIndicator extends ImageView { + + private Drawable[] mIcons; + private CharSequence[] mModes; + + public IconIndicator(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + TypedArray a = context + .obtainStyledAttributes(attrs, R.styleable.IconIndicator, defStyle, 0); + Drawable icons[] = loadIcons(context.getResources(), a.getResourceId( + R.styleable.IconIndicator_icons, 0)); + CharSequence modes[] = a.getTextArray(R.styleable.IconIndicator_modes); + a.recycle(); + + setModesAndIcons(modes, icons); + setImageDrawable(mIcons.length > 0 ? mIcons[0] : null); + } + + public IconIndicator(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + private Drawable[] loadIcons(Resources resources, int iconsId) { + TypedArray array = resources.obtainTypedArray(iconsId); + int n = array.length(); + Drawable drawable[] = new Drawable[n]; + for (int i = 0; i < n; ++i) { + int id = array.getResourceId(i, 0); + drawable[i] = id == 0 ? null : resources.getDrawable(id); + } + array.recycle(); + return drawable; + } + + private void setModesAndIcons(CharSequence[] modes, Drawable icons[]) { + if (modes.length != icons.length || icons.length == 0) { + throw new IllegalArgumentException(); + } + mIcons = icons; + mModes = modes; + } + + public void setMode(String mode) { + for (int i = 0, n = mModes.length; i < n; ++i) { + if (mModes[i].equals(mode)) { + setImageDrawable(mIcons[i]); + return; + } + } + throw new IllegalArgumentException("unknown mode: " + mode); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/LoadScreennailTask.java b/samples/PhotoEditor/src/com/android/photoeditor/LoadScreennailTask.java new file mode 100644 index 0000000..89ba0e2 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/LoadScreennailTask.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.AsyncTask; +import android.widget.Toast; + +/** + * Asynchronous task for loading source photo screennail. + */ +public class LoadScreennailTask extends AsyncTask<Uri, Void, Bitmap> { + + /** + * Callback for the completed asynchronous task. + */ + public interface Callback { + + void onComplete(Bitmap bitmap); + } + + // TODO: Support 1280x960 once OOM is fixed. + private static final int SCREENNAIL_WIDTH = 1024; + private static final int SCREENNAIL_HEIGHT = 768; + + private final Context context; + private final Callback callback; + + public LoadScreennailTask(Context context, Callback callback) { + this.context = context; + this.callback = callback; + } + + /** + * The task should be executed with one given source photo uri. + */ + @Override + protected Bitmap doInBackground(Uri... params) { + if (params[0] == null) { + return null; + } + return new BitmapUtils(context).getBitmap(params[0], SCREENNAIL_WIDTH, SCREENNAIL_HEIGHT); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap == null) { + Toast.makeText(context, R.string.loading_failure, Toast.LENGTH_SHORT).show(); + } + callback.onComplete(bitmap); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/Photo.java b/samples/PhotoEditor/src/com/android/photoeditor/Photo.java new file mode 100644 index 0000000..07898a9 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/Photo.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.graphics.Bitmap; +import android.graphics.Matrix; + +/** + * Photo that is used for editing/display and should be synchronized for concurrent access. + */ +public class Photo { + + private Bitmap bitmap; + + /** + * Factory method to ensure every Photo instance holds a non-null bitmap. + */ + public static Photo create(Bitmap bitmap) { + return (bitmap != null) ? new Photo(bitmap) : null; + } + + private Photo(Bitmap bitmap) { + this.bitmap = bitmap; + } + + public Bitmap bitmap() { + return bitmap; + } + + public Photo copy(Bitmap.Config config) { + Bitmap copy = bitmap.copy(config, true); + return (copy != null) ? new Photo(copy) : null; + } + + public boolean matchDimension(Photo photo) { + return ((photo.width() == width()) && (photo.height() == height())); + } + + public int width() { + return bitmap.getWidth(); + } + + public int height() { + return bitmap.getHeight(); + } + + public void transform(Matrix matrix) { + // Copy immutable transformed photo; no-op if it fails to ensure bitmap isn't assigned null. + Bitmap transformed = BitmapUtils.createBitmap(bitmap, matrix).copy( + bitmap.getConfig(), true); + if (transformed != null) { + bitmap.recycle(); + bitmap = transformed; + } + } + + public void crop(int left, int top, int width, int height) { + // Copy immutable cropped photo; no-op if it fails to ensure bitmap isn't assigned null. + Bitmap cropped = Bitmap.createBitmap(bitmap, left, top, width, height).copy( + bitmap.getConfig(), true); + if (cropped != null) { + bitmap.recycle(); + bitmap = cropped; + } + } + + /** + * Recycles bitmaps; this instance should not be used after its clear() is called. + */ + public void clear() { + bitmap.recycle(); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/PhotoEditor.java b/samples/PhotoEditor/src/com/android/photoeditor/PhotoEditor.java new file mode 100644 index 0000000..928f523 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/PhotoEditor.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import java.io.IOException; +import java.io.InputStream; + +import com.android.photoeditor.filters.ImageUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.view.View; + +/** + * Main activity of the photo editor. + */ +public class PhotoEditor extends Activity { + + private Toolbar toolbar; + private View backButton; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + { + // HACK: create faked view in order to read bitcode in resource + View view = new View(getApplication()); + byte[] pgm; + int pgmLength; + + // read bitcode in res + InputStream is = view.getResources().openRawResource(R.raw.libjni_photoeditor_portable); + try { + try { + pgm = new byte[1024]; + pgmLength = 0; + + while(true) { + int bytesLeft = pgm.length - pgmLength; + if (bytesLeft == 0) { + byte[] buf2 = new byte[pgm.length * 2]; + System.arraycopy(pgm, 0, buf2, 0, pgm.length); + pgm = buf2; + bytesLeft = pgm.length - pgmLength; + } + int bytesRead = is.read(pgm, pgmLength, bytesLeft); + if (bytesRead <= 0) { + break; + } + pgmLength += bytesRead; + } + ImageUtils.init(pgm, pgmLength); + } finally { + is.close(); + } + } catch(IOException e) { + throw new Resources.NotFoundException(); + } + } + + toolbar = (Toolbar) findViewById(R.id.toolbar); + toolbar.initialize(); + + final EffectsBar effectsBar = (EffectsBar) findViewById(R.id.effects_bar); + final View actionBar = findViewById(R.id.action_bar); + final View quickviewOn = findViewById(R.id.quickview_on_button); + backButton = findViewById(R.id.action_bar_back); + backButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + if (actionBar.isEnabled()) { + if (quickviewOn.getVisibility() == View.VISIBLE) { + quickviewOn.performClick(); + } else if (effectsBar.hasEffectOn()) { + effectsBar.effectsOff(null); + } else { + tryRun(new Runnable() { + + @Override + public void run() { + finish(); + } + }); + } + } + } + }); + + Intent intent = getIntent(); + if (Intent.ACTION_EDIT.equalsIgnoreCase(intent.getAction()) && (intent.getData() != null)) { + toolbar.openPhoto(intent.getData()); + } + } + + private void tryRun(final Runnable runnable) { + if (findViewById(R.id.save_button).isEnabled()) { + // Pop-up a dialog before executing the runnable to save unsaved photo. + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + toolbar.savePhoto(new Runnable() { + + @Override + public void run() { + runnable.run(); + } + }); + } + }) + .setNeutralButton(R.string.no, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + runnable.run(); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + // no-op + } + }); + builder.setMessage(R.string.save_photo).show(); + return; + } + + runnable.run(); + } + + @Override + public void onBackPressed() { + backButton.performClick(); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/PhotoOutputCallback.java b/samples/PhotoEditor/src/com/android/photoeditor/PhotoOutputCallback.java new file mode 100644 index 0000000..75651f3 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/PhotoOutputCallback.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +/** + * Callback of photo output that will only be called in UI thread. + */ +public interface PhotoOutputCallback { + + void onReady(Photo photo); +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/PhotoView.java b/samples/PhotoEditor/src/com/android/photoeditor/PhotoView.java new file mode 100644 index 0000000..1853d7c --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/PhotoView.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Animation; + +import com.android.photoeditor.animation.AnimationPair; + +/** + * Displays photo in the view. All its methods should be called from UI thread. + */ +public class PhotoView extends View { + + private final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); + private final Matrix displayMatrix = new Matrix(); + private Photo photo; + private RectF clipBounds; + private AnimationPair transitions; + + public PhotoView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (photo != null) { + canvas.save(); + if (clipBounds != null) { + canvas.clipRect(clipBounds); + } + canvas.concat(displayMatrix); + canvas.drawBitmap(photo.bitmap(), 0, 0, paint); + canvas.restore(); + } + } + + /** + * Maps x and y to a percentage position relative to displayed photo. + */ + public PointF mapPhotoPoint(float x, float y) { + if ((photo == null) || (photo.width() == 0) || (photo.height() == 0)) { + return new PointF(); + } + float[] point = new float[] {x, y}; + Matrix matrix = new Matrix(); + displayMatrix.invert(matrix); + matrix.mapPoints(point); + return new PointF(point[0] / photo.width(), point[1] / photo.height()); + } + + public void mapPhotoPath(Path src, Path dst) { + // TODO: Use percentages representing paths for saving photo larger than previewed photo. + Matrix matrix = new Matrix(); + displayMatrix.invert(matrix); + src.transform(matrix, dst); + } + + public RectF getPhotoDisplayBounds() { + RectF bounds = getPhotoBounds(); + displayMatrix.mapRect(bounds); + return bounds; + } + + public RectF getPhotoBounds() { + return (photo != null) ? new RectF(0, 0, photo.width(), photo.height()) : new RectF(); + } + + /** + * Transforms display by replacing the display matrix of photo-view with the given matrix. + */ + public void transformDisplay(Matrix matrix) { + RectF bounds = getPhotoBounds(); + matrix.mapRect(bounds); + displayMatrix.set(matrix); + RectUtils.postCenterMatrix(bounds, this, displayMatrix); + invalidate(); + } + + public void clipPhoto(RectF bounds) { + clipBounds = bounds; + invalidate(); + } + + /** + * Updates the photo with animations (if any) and also updates photo display-matrix. + */ + public void update(final Photo photo) { + if (transitions == null) { + setPhoto(photo); + invalidate(); + } else if (getAnimation() != null) { + // Clear old running transitions. + clearTransitionAnimations(); + setPhoto(photo); + invalidate(); + } else { + // TODO: Use AnimationSet to chain two animations. + transitions.first().setAnimationListener(new Animation.AnimationListener() { + + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + @Override + public void onAnimationEnd(final Animation animation) { + post(new Runnable() { + + @Override + public void run() { + if ((transitions != null) && (animation == transitions.first())) { + startAnimation(transitions.second()); + } + } + }); + } + }); + transitions.second().setAnimationListener(new Animation.AnimationListener() { + + @Override + public void onAnimationStart(Animation animation) { + setPhoto(photo); + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + post(new Runnable() { + + @Override + public void run() { + clearTransitionAnimations(); + } + }); + } + }); + startAnimation(transitions.first()); + } + } + + private void setPhoto(Photo photo) { + if (this.photo != null) { + this.photo.clear(); + this.photo = null; + } + this.photo = photo; + + // Scale-down (if necessary) and center the photo for display. + displayMatrix.reset(); + RectF bounds = getPhotoBounds(); + float scale = RectUtils.getDisplayScale(bounds, this); + displayMatrix.setScale(scale, scale); + displayMatrix.mapRect(bounds); + RectUtils.postCenterMatrix(bounds, this, displayMatrix); + } + + private void clearTransitionAnimations() { + if (transitions != null) { + transitions.first().setAnimationListener(null); + transitions.second().setAnimationListener(null); + transitions = null; + clearAnimation(); + } + } + + /** + * Sets transition animations in the next update() to transit out the current bitmap and + * transit in the new replacing one. Transition animations will be cleared once done. + */ + public void setTransitionAnimations(AnimationPair transitions) { + clearTransitionAnimations(); + this.transitions = transitions; + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/RectUtils.java b/samples/PhotoEditor/src/com/android/photoeditor/RectUtils.java new file mode 100644 index 0000000..e3945ca --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/RectUtils.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.View; + +/** + * Utils for rectangles/bounds related calculations. + */ +public class RectUtils { + + private static final float MATH_PI = (float) Math.PI; + private static final float DEGREES_TO_RADIAN = MATH_PI / 180.0f; + + /** + * Gets straighten matrix for the given bounds and degrees. + */ + public static void getStraightenMatrix(RectF bounds, float degrees, Matrix matrix) { + matrix.reset(); + if ((degrees != 0) && !bounds.isEmpty()) { + float w = bounds.width() / 2; + float h = bounds.height() / 2; + float adjustAngle; + if ((degrees < 0 && w > h) || (degrees > 0 && w <= h)) { + // The top left point is the boundary. + adjustAngle = (float) Math.atan(h / -w) + MATH_PI + degrees * DEGREES_TO_RADIAN; + } else { + // The top right point is the boundary. + adjustAngle = (float) Math.atan(h / w) - MATH_PI + degrees * DEGREES_TO_RADIAN; + } + float radius = (float) Math.hypot(w, h); + float scaleX = (float) Math.abs(radius * Math.cos(adjustAngle)) / w; + float scaleY = (float) Math.abs(radius * Math.sin(adjustAngle)) / h; + float scale = Math.max(scaleX, scaleY); + + postRotateMatrix(degrees, new RectF(bounds), matrix); + matrix.postScale(scale, scale); + } + } + + /** + * Post rotates the matrix and bounds for the given bounds and degrees. + */ + public static void postRotateMatrix(float degrees, RectF bounds, Matrix matrix) { + matrix.postRotate(degrees); + matrix.mapRect(bounds); + matrix.postTranslate(-bounds.left, -bounds.top); + } + + /** + * Post translates the matrix to center the given bounds inside the view. + */ + public static void postCenterMatrix(RectF contentBounds, View view, Matrix matrix) { + matrix.postTranslate((view.getWidth() - contentBounds.width()) / 2, + (view.getHeight() - contentBounds.height()) / 2); + } + + /** + * Gets the proper scale value that scales down the content and keeps its aspect ratio to + * display inside the view. + */ + public static float getDisplayScale(RectF contentBounds, View view) { + if (contentBounds.isEmpty()) { + return 1; + } + + float scale = Math.min(view.getWidth() / contentBounds.width(), + view.getHeight() / contentBounds.height()); + // Avoid scaling up the content. + return Math.min(scale, 1); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/SaveCopyTask.java b/samples/PhotoEditor/src/com/android/photoeditor/SaveCopyTask.java new file mode 100644 index 0000000..3706600 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/SaveCopyTask.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap.CompressFormat; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Environment; +import android.provider.MediaStore.Images; +import android.provider.MediaStore.Images.ImageColumns; +import android.widget.Toast; + +import java.io.File; +import java.sql.Date; +import java.text.SimpleDateFormat; + +/** + * Asynchronous task for loading source photo in target dimensions and saving edits as a new copy. + */ +public class SaveCopyTask extends AsyncTask<Photo, Void, Uri> { + + /** + * Callback for the completed asynchronous task. + */ + public interface Callback { + + void onComplete(Uri uri); + } + + private static final String TIME_STAMP_NAME = "'IMG'_yyyyMMdd_HHmmss"; + private static final int INDEX_DATE_TAKEN = 0; + private static final int INDEX_LATITUDE = 1; + private static final int INDEX_LONGITUDE = 2; + + private static final String[] IMAGE_PROJECTION = new String[] { + ImageColumns.DATE_TAKEN, + ImageColumns.LATITUDE, + ImageColumns.LONGITUDE, + }; + + private final Context context; + private final Uri sourceUri; + private final Callback callback; + private final String saveFileName; + + public SaveCopyTask(Context context, Uri sourceUri, Callback callback) { + this.context = context; + this.sourceUri = sourceUri; + this.callback = callback; + + saveFileName = new SimpleDateFormat(TIME_STAMP_NAME).format( + new Date(System.currentTimeMillis())); + } + + /** + * The task should be executed with one given photo to be saved. + */ + @Override + protected Uri doInBackground(Photo... params) { + // TODO: Support larger dimensions for photo saving. + if (params[0] == null) { + return null; + } + Photo photo = params[0]; + File file = save(photo); + Uri uri = (file != null) ? insertContent(file) : null; + photo.clear(); + return uri; + } + + @Override + protected void onPostExecute(Uri result) { + String message = (result == null) ? context.getString(R.string.saving_failure) + : context.getString(R.string.photo_saved, saveFileName); + Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); + + callback.onComplete(result); + } + + private File save(Photo photo) { + String directory = Environment.getExternalStorageDirectory().toString() + "/" + + context.getString(R.string.edited_photo_bucket_name); + + return new BitmapUtils(context).saveBitmap( + photo.bitmap(), directory, saveFileName, CompressFormat.JPEG); + } + + /** + * Insert the content (saved file) with proper source photo properties. + */ + private Uri insertContent(File file) { + long now = System.currentTimeMillis() / 1000; + long dateTaken = now; + double latitude = 0f; + double longitude = 0f; + + ContentResolver contentResolver = context.getContentResolver(); + Cursor cursor = contentResolver.query( + sourceUri, IMAGE_PROJECTION, null, null, null); + if ((cursor != null) && cursor.moveToNext()) { + dateTaken = cursor.getLong(INDEX_DATE_TAKEN); + latitude = cursor.getDouble(INDEX_LATITUDE); + longitude = cursor.getDouble(INDEX_LONGITUDE); + } + + ContentValues values = new ContentValues(); + values.put(Images.Media.TITLE, saveFileName); + values.put(Images.Media.DISPLAY_NAME, saveFileName); + values.put(Images.Media.MIME_TYPE, "image/jpeg"); + values.put(Images.Media.DATE_TAKEN, dateTaken); + values.put(Images.Media.DATE_MODIFIED, now); + values.put(Images.Media.DATE_ADDED, now); + values.put(Images.Media.ORIENTATION, 0); + values.put(Images.Media.DATA, file.getAbsolutePath()); + values.put(Images.Media.SIZE, file.length()); + + // TODO: Change || to && after the default location issue is fixed. + if ((latitude != 0f) || (longitude != 0f)) { + values.put(Images.Media.LATITUDE, latitude); + values.put(Images.Media.LONGITUDE, longitude); + } + return contentResolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/SpinnerProgressDialog.java b/samples/PhotoEditor/src/com/android/photoeditor/SpinnerProgressDialog.java new file mode 100644 index 0000000..4e29298 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/SpinnerProgressDialog.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.app.Dialog; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.ProgressBar; + +/** + * Spinner model progress dialog that disables all tools for user interaction after it shows up and + * and re-enables them after it dismisses. + */ +public class SpinnerProgressDialog extends Dialog { + + private final ViewGroup tools; + + public static SpinnerProgressDialog show(ViewGroup tools) { + SpinnerProgressDialog dialog = new SpinnerProgressDialog(tools); + dialog.show(); + return dialog; + } + + private SpinnerProgressDialog(ViewGroup tools) { + super(tools.getContext(), R.style.SpinnerProgressDialog); + + addContentView(new ProgressBar(tools.getContext()), new LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + + this.tools = tools; + enableTools(false); + } + + @Override + public void dismiss() { + super.dismiss(); + + enableTools(true); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + + // Pass touch events to tools for killing idle even when the progress dialog is shown. + return tools.onInterceptTouchEvent(event); + } + + private void enableTools(boolean enabled) { + for (int i = 0; i < tools.getChildCount(); i++) { + tools.getChildAt(i).setEnabled(enabled); + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/Toolbar.java b/samples/PhotoEditor/src/com/android/photoeditor/Toolbar.java new file mode 100644 index 0000000..106cf75 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/Toolbar.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.RelativeLayout; + +import com.android.photoeditor.animation.FadeAnimation; +import com.android.photoeditor.animation.Rotate3DAnimation; +import com.android.photoeditor.animation.Rotate3DAnimation.Rotate; + +/** + * Toolbar that contains all tools and handles all operations for editing photo. + */ +public class Toolbar extends RelativeLayout { + + private static final int UNDO_REDO_ANIMATION_DURATION = 100; + private static final int QUICKVIEW_ANIMATION_DURATION = 150; + + private final FilterStack filterStack = new FilterStack(); + private ToolbarLayoutHandler layoutHandler; + private ToolbarIdleHandler idleHandler; + private EffectsBar effectsBar; + private ActionBar actionBar; + private PhotoView photoView; + private SpinnerProgressDialog progressDialog; + private Uri sourceUri; + + public Toolbar(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + idleHandler.killIdle(); + return false; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + layoutHandler.extraLayout(l, t, r, b); + } + + public void initialize() { + photoView = (PhotoView) findViewById(R.id.photo_view); + initializeEffectsBar(); + initializeActionBar(); + layoutHandler = new ToolbarLayoutHandler(this); + idleHandler = new ToolbarIdleHandler(this); + idleHandler.killIdle(); + } + + private void initializeEffectsBar() { + effectsBar = (EffectsBar) findViewById(R.id.effects_bar); + effectsBar.initialize(filterStack, photoView, this); + } + + private void initializeActionBar() { + final PhotoOutputCallback callback = new PhotoOutputCallback() { + + @Override + public void onReady(Photo photo) { + photoView.setTransitionAnimations( + FadeAnimation.getFadeOutInAnimations(UNDO_REDO_ANIMATION_DURATION)); + photoView.update(photo); + progressDialog.dismiss(); + } + }; + + actionBar = (ActionBar) findViewById(R.id.action_bar); + actionBar.initialize(new ActionBar.ActionBarListener() { + + @Override + public void onUndo() { + effectsBar.effectsOff(new Runnable() { + + @Override + public void run() { + progressDialog = SpinnerProgressDialog.show(Toolbar.this); + filterStack.undo(callback); + } + }); + } + + @Override + public void onRedo() { + effectsBar.effectsOff(new Runnable() { + + @Override + public void run() { + progressDialog = SpinnerProgressDialog.show(Toolbar.this); + filterStack.redo(callback); + } + }); + } + + @Override + public void onQuickview(final boolean on) { + final PhotoOutputCallback callback = new PhotoOutputCallback() { + + @Override + public void onReady(Photo photo) { + photoView.setTransitionAnimations(Rotate3DAnimation.getFlipAnimations( + on ? Rotate.RIGHT : Rotate.LEFT, QUICKVIEW_ANIMATION_DURATION)); + photoView.update(photo); + } + }; + + if (on) { + effectsBar.effectsOff(new Runnable() { + + @Override + public void run() { + effectsBar.setVisibility(INVISIBLE); + filterStack.getSourceCopy(callback); + } + }); + } else { + effectsBar.setVisibility(VISIBLE); + filterStack.getResultCopy(callback); + } + } + + @Override + public void onSave() { + effectsBar.effectsOff(new Runnable() { + + @Override + public void run() { + savePhoto(null); + } + }); + } + }); + } + + public void openPhoto(Uri uri) { + sourceUri = uri; + filterStack.setStackListener(actionBar); + + // clearPhotoSource() should be called before loading a new source photo to avoid OOM. + progressDialog = SpinnerProgressDialog.show(this); + filterStack.clearPhotoSource(); + new LoadScreennailTask(getContext(), new LoadScreennailTask.Callback() { + + @Override + public void onComplete(Bitmap bitmap) { + filterStack.setPhotoSource(Photo.create(bitmap)); + filterStack.getResultCopy(new PhotoOutputCallback() { + + @Override + public void onReady(Photo photo) { + photoView.update(photo); + progressDialog.dismiss(); + effectsBar.setEnabled(photo != null); + } + }); + } + }).execute(sourceUri); + } + + /** + * Saves photo and executes runnable (if provided) after saving done. + */ + public void savePhoto(final Runnable runnable) { + progressDialog = SpinnerProgressDialog.show(this); + filterStack.getResultCopy(new PhotoOutputCallback() { + + @Override + public void onReady(Photo photo) { + new SaveCopyTask(getContext(), sourceUri, new SaveCopyTask.Callback() { + + @Override + public void onComplete(Uri uri) { + // TODO: Handle saving failure. + progressDialog.dismiss(); + actionBar.disableSave(); + if (runnable != null) { + runnable.run(); + } + } + }).execute(photo); + } + }); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/ToolbarIdleHandler.java b/samples/PhotoEditor/src/com/android/photoeditor/ToolbarIdleHandler.java new file mode 100644 index 0000000..07b8f50 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/ToolbarIdleHandler.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Handler that controls idle/awake behaviors of toolbar's child views. + */ +class ToolbarIdleHandler { + + private static final String IDLE_VIEW_TAG = "fadeOnIdle"; + private static final int MAKE_IDLE = 1; + private static final int TIMEOUT_IDLE = 8000; + + private final List<View> childViews = new ArrayList<View>(); + private final Handler mainHandler; + private final Animation fadeIn; + private final Animation fadeOut; + private boolean idle; + + /** + * Constructor should only be invoked after toolbar has done inflation and added all its child + * views; then its child views could be found by findViewById calls. + */ + public ToolbarIdleHandler(ViewGroup toolbar) { + mainHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MAKE_IDLE: + if (!idle) { + idle = true; + for (View view : childViews) { + makeIdle(view); + } + } + break; + } + } + }; + + fadeIn = AnimationUtils.loadAnimation(toolbar.getContext(), R.anim.fade_in); + fadeOut = AnimationUtils.loadAnimation(toolbar.getContext(), R.anim.fade_out); + + for (int i = 0; i < toolbar.getChildCount(); i++) { + View view = toolbar.getChildAt(i); + String tag = (String) view.getTag(); + if ((tag != null) && tag.equals(IDLE_VIEW_TAG)) { + childViews.add(view); + } + } + // Alpha animations don't work well on scroll-view; apply them on container linear-layout. + childViews.add(toolbar.findViewById(R.id.effects_container)); + } + + public void killIdle() { + mainHandler.removeMessages(MAKE_IDLE); + if (idle) { + idle = false; + for (View view : childViews) { + makeAwake(view); + } + } + mainHandler.sendEmptyMessageDelayed(MAKE_IDLE, TIMEOUT_IDLE); + } + + private void makeAwake(View view) { + if (view.getVisibility() == View.VISIBLE) { + view.startAnimation(fadeIn); + } + } + + private void makeIdle(View view) { + if (view.getVisibility() == View.VISIBLE) { + view.startAnimation(fadeOut); + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/ToolbarLayoutHandler.java b/samples/PhotoEditor/src/com/android/photoeditor/ToolbarLayoutHandler.java new file mode 100644 index 0000000..93253d7 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/ToolbarLayoutHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor; + +import android.view.View; + +/** + * Handler that adjusts layouts of toolbar's child views whose positions need being calculated + * according to the current screen dimensions. + */ +class ToolbarLayoutHandler { + + private final View tools; + + /** + * Constructor should only be invoked after toolbar has done inflation and added all its child + * views; then its child views could be found by findViewById calls. + */ + public ToolbarLayoutHandler(View toolbar) { + this.tools = toolbar; + } + + /** + * Layouts child tool views' positions that need being updated when toolbar is being layout. + */ + public void extraLayout(int left, int top, int right, int bottom) { + // Wheels need being centered vertically. + int height = bottom - top; + + View scaleWheel = tools.findViewById(R.id.scale_wheel); + scaleWheel.offsetTopAndBottom((height - scaleWheel.getHeight()) / 2); + + View colorWheel = tools.findViewById(R.id.color_wheel); + colorWheel.offsetTopAndBottom((height - colorWheel.getHeight()) / 2); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/AutoFixAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/AutoFixAction.java new file mode 100644 index 0000000..0c9f174 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/AutoFixAction.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.AutoFixFilter; + +/** + * An action handling auto-fix effect. + */ +public class AutoFixAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0.5f; + + public AutoFixAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final AutoFixFilter filter = new AutoFixFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setScale(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + + filter.setScale(DEFAULT_SCALE); + notifyFilterChanged(filter, true); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorPath.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorPath.java new file mode 100644 index 0000000..1aedfb6 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorPath.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; + +/** + * Colored path that could be painted on canvas. + */ +public class ColorPath { + + private final int color; + private final Path path; + + public ColorPath(int color, Path path) { + this.color = Color.argb(192, Color.red(color), Color.green(color), Color.blue(color)); + this.path = path; + } + + public Path path() { + return path; + } + + public void draw(Canvas canvas, Paint paint) { + paint.setColor(color); + canvas.drawPath(path, paint); + } + + /** + * Creates a paint to draw color paths. + */ + public static Paint createPaint() { + Paint paint = new Paint(Paint.DITHER_FLAG | Paint.ANTI_ALIAS_FLAG); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeJoin(Paint.Join.ROUND); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStrokeWidth(12); + return paint; + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorTemperatureAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorTemperatureAction.java new file mode 100644 index 0000000..db2850f --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorTemperatureAction.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.ColorTemperatureFilter; + +/** + * An action handling color temperature effect. + */ +public class ColorTemperatureAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0.5f; + + public ColorTemperatureAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final ColorTemperatureFilter filter = new ColorTemperatureFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setColorTemperature(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorWheel.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorWheel.java new file mode 100644 index 0000000..7c7e715 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/ColorWheel.java @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AnimationUtils; + +import com.android.photoeditor.R; + +/** + * Wheel that has a draggable thumb to set and get the predefined color set. + */ +class ColorWheel extends View { + + /** + * Listens to color changes. + */ + public interface OnColorChangeListener { + + void onColorChanged(int color, boolean fromUser); + } + + private static final float MATH_PI = (float) Math.PI; + private static final float MATH_HALF_PI = MATH_PI / 2; + + // All angles used in this object are defined between PI and -PI. + private static final float ANGLE_SPANNED = MATH_PI * 4 / 3; + private static final float ANGLE_BEGIN = ANGLE_SPANNED / 2.0f; + private static final float DEGREES_BEGIN = 360 - (float) Math.toDegrees(ANGLE_BEGIN); + private static final float STROKE_WIDTH = 3.0f; + + private static final float THUMB_RADIUS_RATIO = 0.363f; + private static final float INNER_RADIUS_RATIO = 0.173f; + + private static final int PADDING = 4; + private static final int COLOR_METER_THICKNESS = 18; + + private final Drawable thumb; + private final Paint fillPaint; + private final Paint strokePaint; + private final int thumbSize; + private final int borderColor; + private final int[] colorsDefined; + private final float radiantInterval; + private Bitmap background; + private int thumbRadius; + private int innerRadius; + private int centerXY; + private int colorIndex; + private float angle; + private boolean dragThumb; + private OnColorChangeListener listener; + + public ColorWheel(Context context, AttributeSet attrs) { + super(context, attrs); + + Resources resources = context.getResources(); + thumbSize = (int) resources.getDimension(R.dimen.wheel_thumb_size); + + // Set the number of total colors and compute the radiant interval between colors. + TypedArray colors = resources.obtainTypedArray(R.array.color_picker_wheel_colors); + colorsDefined = new int[colors.length()]; + for (int c = 0; c < colors.length(); c++) { + colorsDefined[c] = colors.getColor(c, 0x000000); + } + colors.recycle(); + + radiantInterval = ANGLE_SPANNED / colorsDefined.length; + + thumb = resources.getDrawable(R.drawable.wheel_knot_selector); + borderColor = resources.getColor(R.color.color_picker_border_color); + + fillPaint = new Paint(); + fillPaint.setAntiAlias(true); + fillPaint.setStyle(Paint.Style.FILL); + strokePaint = new Paint(); + strokePaint.setAntiAlias(true); + strokePaint.setStrokeWidth(STROKE_WIDTH); + strokePaint.setStyle(Paint.Style.STROKE); + } + + public void setColorIndex(int colorIndex) { + if (updateColorIndex(colorIndex, false)) { + updateThumbPositionByColorIndex(); + } + } + + public int getColor() { + return colorsDefined[colorIndex]; + } + + public void setOnColorChangeListener(OnColorChangeListener listener) { + this.listener = listener; + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + + startAnimation(AnimationUtils.loadAnimation(getContext(), + (visibility == VISIBLE) ? R.anim.wheel_show : R.anim.wheel_hide)); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + int wheelSize = Math.min(w, h) - PADDING; + thumbRadius = (int) (wheelSize * THUMB_RADIUS_RATIO); + innerRadius = (int) (wheelSize * INNER_RADIUS_RATIO); + + // The wheel would be centered at (centerXY, centerXY) and have outer-radius centerXY. + centerXY = wheelSize / 2; + updateThumbPositionByColorIndex(); + } + + private Bitmap prepareBackground() { + int diameter = centerXY * 2; + Bitmap bitmap = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + // the colors to be selected. + float radiantDegrees = (float) Math.toDegrees(radiantInterval); + RectF drawBound = new RectF(0, 0, diameter, diameter); + for (int c = 0; c < colorsDefined.length; c++) { + fillPaint.setColor(colorsDefined[c]); + canvas.drawArc(drawBound, DEGREES_BEGIN + radiantDegrees * c, + radiantDegrees, true, fillPaint); + } + + // clear the inner area. + fillPaint.setColor(Color.BLACK); + fillPaint.setAlpha(160); + canvas.drawCircle(centerXY, centerXY, centerXY - COLOR_METER_THICKNESS, fillPaint); + + // the border for the inner ball + fillPaint.setColor(borderColor); + canvas.drawCircle(centerXY, centerXY, innerRadius + STROKE_WIDTH, fillPaint); + + return bitmap; + } + + private void drawBackground(Canvas canvas) { + if (background == null) { + background = prepareBackground(); + } + canvas.drawBitmap(background, 0, 0, fillPaint); + } + + private void drawHighlighter(Canvas canvas) { + strokePaint.setColor(borderColor); + int diameter = centerXY * 2; + RectF drawBound = new RectF(0, 0, diameter, diameter); + float radiantDegrees = (float) Math.toDegrees(radiantInterval); + float startAngle = DEGREES_BEGIN + radiantDegrees * colorIndex; + canvas.drawArc(drawBound, startAngle, radiantDegrees, false, strokePaint); + drawBound.inset(COLOR_METER_THICKNESS, COLOR_METER_THICKNESS); + canvas.drawArc(drawBound, startAngle, radiantDegrees, false, strokePaint); + + float lineAngle = ANGLE_BEGIN - radiantInterval * colorIndex; + float cosAngle = (float) Math.cos(lineAngle); + float sinAngle = (float) Math.sin(lineAngle); + int innerRadius = centerXY - COLOR_METER_THICKNESS; + canvas.drawLine(centerXY + centerXY * cosAngle, centerXY - centerXY * sinAngle, + centerXY + innerRadius * cosAngle, + centerXY - innerRadius * sinAngle, strokePaint); + + lineAngle -= radiantInterval; + cosAngle = (float) Math.cos(lineAngle); + sinAngle = (float) Math.sin(lineAngle); + canvas.drawLine(centerXY + centerXY * cosAngle, centerXY - centerXY * sinAngle, + centerXY + innerRadius * cosAngle, + centerXY - innerRadius * sinAngle, strokePaint); + } + + private void drawInnerCircle(Canvas canvas) { + fillPaint.setColor(colorsDefined[colorIndex]); + canvas.drawCircle(centerXY, centerXY, innerRadius, fillPaint); + } + + private void drawThumb(Canvas canvas) { + int thumbX = (int) (thumbRadius * Math.cos(angle) + centerXY); + int thumbY = (int) (centerXY - thumbRadius * Math.sin(angle)); + int halfSize = thumbSize / 2; + thumb.setBounds(thumbX - halfSize, thumbY - halfSize, thumbX + halfSize, thumbY + halfSize); + thumb.draw(canvas); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + drawBackground(canvas); + drawInnerCircle(canvas); + drawHighlighter(canvas); + drawThumb(canvas); + } + + private boolean updateAngle(float x, float y) { + float angle; + if (x == 0) { + if (y >= 0) { + angle = MATH_HALF_PI; + } else { + angle = -MATH_HALF_PI; + } + } else { + angle = (float) Math.atan((double) y / x); + } + + if (angle >= 0 && x < 0) { + angle = angle - MATH_PI; + } else if (angle < 0 && x < 0) { + angle = MATH_PI + angle; + } + + if (angle > ANGLE_BEGIN || angle <= ANGLE_BEGIN - ANGLE_SPANNED) { + return false; + } + + this.angle = angle; + return true; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + + if (isEnabled()) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + updateThumbState( + isHittingThumbArea(ev.getX() - centerXY, centerXY - ev.getY())); + break; + + case MotionEvent.ACTION_MOVE: + final float x = ev.getX() - centerXY; + final float y = centerXY - ev.getY(); + if (!dragThumb && !updateThumbState(isHittingThumbArea(x, y))) { + // The thumb wasn't dragged and isn't being dragged, either. + break; + } + + if (updateAngle(x, y)) { + int index = (int) ((ANGLE_BEGIN - angle) / radiantInterval); + if (updateColorIndex(index, true)) { + updateThumbPositionByColorIndex(); + } + } + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + updateThumbState(false); + break; + } + } + return true; + } + + /** + * Returns true if the user is hitting the correct thumb area. + */ + private boolean isHittingThumbArea(float x, float y) { + final float radius = (float) Math.sqrt((x * x) + (y * y)); + return (radius > innerRadius) && (radius < centerXY); + } + + + private boolean updateColorIndex(int index, boolean fromUser) { + if (index < 0 || index >= colorsDefined.length) { + return false; + } + if (colorIndex != index) { + colorIndex = index; + + if (listener != null) { + listener.onColorChanged(colorsDefined[colorIndex], fromUser); + } + return true; + } + return false; + } + + /** + * Set the thumb position according to the selected color. + * The thumb will always be placed in the middle of the selected color. + */ + private void updateThumbPositionByColorIndex() { + angle = ANGLE_BEGIN - (colorIndex + 0.5f) * radiantInterval; + invalidate(); + } + + private boolean updateThumbState(boolean dragThumb) { + if (this.dragThumb == dragThumb) { + // The state hasn't been changed; no need for updates. + return false; + } + + this.dragThumb = dragThumb; + thumb.setState(dragThumb ? PRESSED_ENABLED_STATE_SET : ENABLED_STATE_SET); + invalidate(); + return true; + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/CropAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/CropAction.java new file mode 100644 index 0000000..5e6dd53 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/CropAction.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.graphics.Path; +import android.graphics.RectF; +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.R; +import com.android.photoeditor.filters.CropFilter; + +/** + * An action handling crop effect. + */ +public class CropAction extends FilterAction { + + private static final float DEFAULT_CROP = 0.2f; + private CropFilter filter; + + public CropAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools, R.string.crop_tooltip); + } + + private RectF mapPhotoBounds(RectF bounds, RectF photoBounds) { + return new RectF((bounds.left - photoBounds.left) / photoBounds.width(), + (bounds.top - photoBounds.top) / photoBounds.height(), + (bounds.right - photoBounds.left) / photoBounds.width(), + (bounds.bottom - photoBounds.top) / photoBounds.height()); + } + + @Override + public void onBegin() { + filter = new CropFilter(); + + final RectF photoBounds = photoView.getPhotoDisplayBounds(); + cropView.setPhotoBounds(new RectF(photoBounds)); + cropView.setOnCropChangeListener(new CropView.OnCropChangeListener() { + + @Override + public void onCropChanged(RectF bounds, boolean fromUser) { + if (fromUser) { + filter.setCropBounds(mapPhotoBounds(bounds, photoBounds)); + notifyFilterChanged(filter, false); + } + } + }); + RectF cropBounds = new RectF(photoBounds); + cropBounds.inset(photoBounds.width() * DEFAULT_CROP, photoBounds.height() * DEFAULT_CROP); + cropView.setCropBounds(cropBounds); + if (!cropView.fullPhotoCropped()) { + filter.setCropBounds(mapPhotoBounds(cropBounds, photoBounds)); + notifyFilterChanged(filter, false); + } + cropView.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + notifyFilterChanged(filter, true); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/CropView.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/CropView.java new file mode 100644 index 0000000..6486c33 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/CropView.java @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.graphics.RegionIterator; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import com.android.photoeditor.R; + +import java.util.Vector; + +/** + * A view that track touch motions and adjust crop bounds accordingly. + */ +class CropView extends View { + + /** + * Listener of crop bounds. + */ + public interface OnCropChangeListener { + + void onCropChanged(RectF bounds, boolean fromUser); + } + + private static final int TOUCH_AREA_NONE = 0; + private static final int TOUCH_AREA_LEFT = 1; + private static final int TOUCH_AREA_TOP = 2; + private static final int TOUCH_AREA_RIGHT = 4; + private static final int TOUCH_AREA_BOTTOM = 8; + private static final int TOUCH_AREA_INSIDE = 15; + private static final int TOUCH_AREA_OUTSIDE = 16; + private static final int TOUCH_AREA_TOP_LEFT = 3; + private static final int TOUCH_AREA_TOP_RIGHT = 6; + private static final int TOUCH_AREA_BOTTOM_LEFT = 9; + private static final int TOUCH_AREA_BOTTOM_RIGHT = 12; + + private static final int BORDER_COLOR = 0xFF008AFF; + private static final int OUTER_COLOR = 0xA0000000; + private static final int INDICATION_COLOR = 0xFFCC9900; + private static final int TOUCH_AREA_SPAN = 20; + private static final int TOUCH_AREA_SPAN2 = TOUCH_AREA_SPAN * 2; + private static final float BORDER_WIDTH = 2.0f; + + private final Paint outerAreaPaint; + private final Paint borderPaint; + private final Paint highlightPaint; + + private final Drawable heightIndicator; + private final Drawable widthIndicator; + private final int indicatorSize; + + private RectF cropBounds; + private RectF photoBounds; + + private OnCropChangeListener listener; + + private float lastX; + private float lastY; + private int currentTouchArea; + + public CropView(Context context, AttributeSet attrs) { + super(context, attrs); + + Resources resources = context.getResources(); + heightIndicator = resources.getDrawable(R.drawable.crop_height_holo); + widthIndicator = resources.getDrawable(R.drawable.crop_width_holo); + indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size); + + outerAreaPaint = new Paint(); + outerAreaPaint.setStyle(Paint.Style.FILL); + outerAreaPaint.setColor(OUTER_COLOR); + + borderPaint = new Paint(); + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setColor(BORDER_COLOR); + borderPaint.setStrokeWidth(BORDER_WIDTH); + + highlightPaint = new Paint(); + highlightPaint.setStyle(Paint.Style.STROKE); + highlightPaint.setColor(INDICATION_COLOR); + highlightPaint.setStrokeWidth(BORDER_WIDTH); + + currentTouchArea = TOUCH_AREA_NONE; + } + + public void setOnCropChangeListener(OnCropChangeListener listener) { + this.listener = listener; + } + + private void notifyCropChange(boolean fromUser) { + if (listener != null) { + listener.onCropChanged(cropBounds, fromUser); + } + } + + public void setCropBounds(RectF bounds) { + bounds.intersect(photoBounds); + cropBounds = bounds; + if (photoBounds.width() <= TOUCH_AREA_SPAN2) { + cropBounds.left = photoBounds.left; + cropBounds.right = photoBounds.right; + } + if (photoBounds.height() <= TOUCH_AREA_SPAN2) { + cropBounds.top = photoBounds.top; + cropBounds.bottom = photoBounds.bottom; + } + notifyCropChange(false); + invalidate(); + } + + /** + * Sets bounds to crop within. + */ + public void setPhotoBounds(RectF bounds) { + photoBounds = bounds; + } + + public boolean fullPhotoCropped() { + return cropBounds.contains(photoBounds); + } + + private int detectTouchArea(float x, float y) { + RectF area = new RectF(); + area.set(cropBounds); + area.inset(-TOUCH_AREA_SPAN, -TOUCH_AREA_SPAN); + if (!area.contains(x, y)) { + return TOUCH_AREA_OUTSIDE; + } + + // left + area.set(cropBounds.left - TOUCH_AREA_SPAN, cropBounds.top + TOUCH_AREA_SPAN, + cropBounds.left + TOUCH_AREA_SPAN, cropBounds.bottom - TOUCH_AREA_SPAN); + if (area.contains(x, y)) { + return TOUCH_AREA_LEFT; + } + // right + area.offset(cropBounds.width(), 0f); + if (area.contains(x, y)) { + return TOUCH_AREA_RIGHT; + } + // top + area.set(cropBounds.left + TOUCH_AREA_SPAN, cropBounds.top - TOUCH_AREA_SPAN, + cropBounds.right - TOUCH_AREA_SPAN, cropBounds.top + TOUCH_AREA_SPAN); + if (area.contains(x, y)) { + return TOUCH_AREA_TOP; + } + // bottom + area.offset(0f, cropBounds.height()); + if (area.contains(x, y)) { + return TOUCH_AREA_BOTTOM; + } + // top left + area.set(cropBounds.left - TOUCH_AREA_SPAN, cropBounds.top - TOUCH_AREA_SPAN, + cropBounds.left + TOUCH_AREA_SPAN, cropBounds.top + TOUCH_AREA_SPAN); + if (area.contains(x, y)) { + return TOUCH_AREA_TOP_LEFT; + } + // top right + area.offset(cropBounds.width(), 0f); + if (area.contains(x, y)) { + return TOUCH_AREA_TOP_RIGHT; + } + // bottom right + area.offset(0f, cropBounds.height()); + if (area.contains(x, y)) { + return TOUCH_AREA_BOTTOM_RIGHT; + } + // bottom left + area.offset(-cropBounds.width(), 0f); + if (area.contains(x, y)) { + return TOUCH_AREA_BOTTOM_LEFT; + } + return TOUCH_AREA_INSIDE; + } + + private void performMove(float deltaX, float deltaY) { + if (currentTouchArea == TOUCH_AREA_INSIDE){ // moving the rect. + cropBounds.offset(deltaX, deltaY); + if (cropBounds.left < photoBounds.left) { + cropBounds.offset(photoBounds.left - cropBounds.left, 0f); + } else if (cropBounds.right > photoBounds.right) { + cropBounds.offset(photoBounds.right - cropBounds.right, 0f); + } + if (cropBounds.top < photoBounds.top) { + cropBounds.offset(0f, photoBounds.top - cropBounds.top); + } else if (cropBounds.bottom > photoBounds.bottom) { + cropBounds.offset(0f, photoBounds.bottom - cropBounds.bottom); + } + } else { // adjusting bounds. + if ((currentTouchArea & TOUCH_AREA_LEFT) != 0) { + cropBounds.left = Math.min(cropBounds.left + deltaX, + cropBounds.right - TOUCH_AREA_SPAN2); + } + if ((currentTouchArea & TOUCH_AREA_TOP) != 0) { + cropBounds.top = Math.min(cropBounds.top + deltaY, + cropBounds.bottom - TOUCH_AREA_SPAN2); + } + if ((currentTouchArea & TOUCH_AREA_RIGHT) != 0) { + cropBounds.right = Math.max(cropBounds.right + deltaX, + cropBounds.left + TOUCH_AREA_SPAN2); + } + if ((currentTouchArea & TOUCH_AREA_BOTTOM) != 0) { + cropBounds.bottom = Math.max(cropBounds.bottom + deltaY, + cropBounds.top + TOUCH_AREA_SPAN2); + } + cropBounds.intersect(photoBounds); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + + if (!isEnabled()) { + return true; + } + float x = event.getX(); + float y = event.getY(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + currentTouchArea = detectTouchArea(x, y); + lastX = x; + lastY = y; + invalidate(); + break; + + case MotionEvent.ACTION_MOVE: + performMove(x - lastX, y - lastY); + + lastX = x; + lastY = y; + notifyCropChange(true); + invalidate(); + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + currentTouchArea = TOUCH_AREA_NONE; + invalidate(); + break; + } + return true; + } + + private void drawIndicator(Canvas canvas, Drawable indicator, float centerX, float centerY) { + int left = (int) centerX - indicatorSize / 2; + int top = (int) centerY - indicatorSize / 2; + int right = left + indicatorSize; + int bottom = top + indicatorSize; + indicator.setBounds(left, top, right, bottom); + indicator.draw(canvas); + } + + private void drawIndicators(Canvas canvas) { + drawIndicator(canvas, heightIndicator, cropBounds.centerX(), cropBounds.top); + drawIndicator(canvas, heightIndicator, cropBounds.centerX(), cropBounds.bottom); + drawIndicator(canvas, widthIndicator, cropBounds.left, cropBounds.centerY()); + drawIndicator(canvas, widthIndicator, cropBounds.right, cropBounds.centerY()); + } + + private void drawTouchHighlights(Canvas canvas) { + if ((currentTouchArea & TOUCH_AREA_TOP) != 0) { + canvas.drawLine(cropBounds.left, cropBounds.top, cropBounds.right, cropBounds.top, + highlightPaint); + } + if ((currentTouchArea & TOUCH_AREA_BOTTOM) != 0) { + canvas.drawLine(cropBounds.left, cropBounds.bottom, cropBounds.right, + cropBounds.bottom, highlightPaint); + } + if ((currentTouchArea & TOUCH_AREA_LEFT) != 0) { + canvas.drawLine(cropBounds.left, cropBounds.top, cropBounds.left, cropBounds.bottom, + highlightPaint); + } + if ((currentTouchArea & TOUCH_AREA_RIGHT) != 0) { + canvas.drawLine(cropBounds.right, cropBounds.top, cropBounds.right, cropBounds.bottom, + highlightPaint); + } + } + + private void drawBounds(Canvas canvas) { + Rect r = new Rect(); + photoBounds.roundOut(r); + Region drawRegion = new Region(r); + cropBounds.roundOut(r); + drawRegion.op(r, Region.Op.DIFFERENCE); + RegionIterator iter = new RegionIterator(drawRegion); + while (iter.next(r)) { + canvas.drawRect(r, outerAreaPaint); + } + + canvas.drawRect(cropBounds, borderPaint); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + drawBounds(canvas); + if (currentTouchArea != TOUCH_AREA_NONE) { + drawTouchHighlights(canvas); + drawIndicators(canvas); + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/CrossProcessAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/CrossProcessAction.java new file mode 100644 index 0000000..c4565ee --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/CrossProcessAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.CrossProcessFilter; + +/** + * An action handling cross-process effect. + */ +public class CrossProcessAction extends FilterAction { + + public CrossProcessAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new CrossProcessFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/DocumentaryAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/DocumentaryAction.java new file mode 100644 index 0000000..b8bd9c6 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/DocumentaryAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.DocumentaryFilter; + +/** + * An action handling the preset "Documentary" effect. + */ +public class DocumentaryAction extends FilterAction { + + public DocumentaryAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new DocumentaryFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/DoodleAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/DoodleAction.java new file mode 100644 index 0000000..16cc37e --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/DoodleAction.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.graphics.Path; +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.R; +import com.android.photoeditor.filters.DoodleFilter; + +/** + * An action handling doodle effect. + */ +public class DoodleAction extends FilterAction { + + private static final int DEFAULT_COLOR_INDEX = 4; + + private DoodleFilter filter; + + public DoodleAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools, R.string.doodle_tooltip); + } + + @Override + public void onBegin() { + filter = new DoodleFilter(); + + colorWheel.setOnColorChangeListener(new ColorWheel.OnColorChangeListener() { + + @Override + public void onColorChanged(int color, boolean fromUser){ + if (fromUser) { + doodleView.startPath(color); + filter.addPath(color); + } + } + }); + colorWheel.setColorIndex(DEFAULT_COLOR_INDEX); + colorWheel.setVisibility(View.VISIBLE); + + // Directly draw on doodle-view instead of waiting for top-filter output callback. + doodleView.setOnDoodleChangeListener(new DoodleView.OnDoodleChangeListener() { + + private final Path transformPath = new Path(); + + @Override + public void onLastPathChanged(Path path) { + photoView.mapPhotoPath(path, transformPath); + filter.updateLastPath(transformPath); + notifyFilterChanged(filter, false); + } + }); + doodleView.clear(); + doodleView.clipBounds(photoView.getPhotoDisplayBounds()); + doodleView.setVisibility(View.VISIBLE); + + int color = colorWheel.getColor(); + doodleView.startPath(color); + + filter.addPath(color); + } + + @Override + public void onEnd() { + notifyFilterChanged(filter, true); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/DoodleView.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/DoodleView.java new file mode 100644 index 0000000..e975965 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/DoodleView.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import java.util.Vector; + +/** + * A view that track touch motions as paths and paint them as doodles. + */ +class DoodleView extends View { + + /** + * Listener of doodle paths. + */ + public interface OnDoodleChangeListener { + + void onLastPathChanged(Path path); + } + + private final Vector<ColorPath> colorPaths = new Vector<ColorPath>(); + private final Paint paint = ColorPath.createPaint(); + + private OnDoodleChangeListener listener; + private RectF clipBounds; + private float lastX; + private float lastY; + + public DoodleView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setOnDoodleChangeListener(OnDoodleChangeListener listener) { + this.listener = listener; + } + + public void startPath(int color) { + // Remove last empty path before adding a new path. + if (!colorPaths.isEmpty() && colorPaths.lastElement().path().isEmpty()) { + colorPaths.remove(colorPaths.size() - 1); + } + colorPaths.add(new ColorPath(color, new Path())); + colorPaths.lastElement().path().moveTo(lastX, lastY); + } + + /** + * Clears clip bounds and paths drawn. + */ + public void clear() { + colorPaths.clear(); + clipBounds = null; + } + + /** + * Clips bounds for paths being drawn. + */ + public void clipBounds(RectF bounds) { + clipBounds = bounds; + } + + private void pathUpdated(Path path) { + invalidate(); + if (listener != null) { + listener.onLastPathChanged(path); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + + if (isEnabled() && !colorPaths.isEmpty()) { + Path path = colorPaths.lastElement().path(); + float x = event.getX(); + float y = event.getY(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + path.moveTo(x, y); + pathUpdated(path); + lastX = x; + lastY = y; + break; + + case MotionEvent.ACTION_MOVE: + path.quadTo(lastX, lastY, (lastX + x) / 2, (lastY + y) / 2); + pathUpdated(path); + lastX = x; + lastY = y; + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + // Line to last position with offset to draw at least dots for single clicks. + path.lineTo(lastX + 1, lastY + 1); + pathUpdated(path); + break; + } + } + return true; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.save(); + if (clipBounds != null) { + canvas.clipRect(clipBounds); + } + for (ColorPath colorPath : colorPaths) { + colorPath.draw(canvas, paint); + } + canvas.restore(); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/DuotoneAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/DuotoneAction.java new file mode 100644 index 0000000..80eaf0f --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/DuotoneAction.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.DuotoneFilter; + +/** + * An action handling duo-tone effect. + */ +public class DuotoneAction extends FilterAction { + + private static final int DEFAULT_FIRST_COLOR = 0x004488; + private static final int DEFAULT_SECOND_COLOR = 0xffff00; + + public DuotoneAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + // TODO: Add several sets of duo-tone colors to select from. + DuotoneFilter filter = new DuotoneFilter(); + filter.setDuotone(DEFAULT_FIRST_COLOR, DEFAULT_SECOND_COLOR); + notifyFilterChanged(filter, true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/FillLightAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/FillLightAction.java new file mode 100644 index 0000000..60ddcd3 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/FillLightAction.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.FillLightFilter; + +/** + * An action handling fill-light effect. + */ +public class FillLightAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0f; + + public FillLightAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final FillLightFilter filter = new FillLightFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setBacklight(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/FilterAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/FilterAction.java new file mode 100644 index 0000000..08c9fd2 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/FilterAction.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.Photo; +import com.android.photoeditor.PhotoOutputCallback; +import com.android.photoeditor.PhotoView; +import com.android.photoeditor.R; +import com.android.photoeditor.SpinnerProgressDialog; +import com.android.photoeditor.filters.Filter; + +/** + * An action binding UI controls and filter operation for editing photo. + */ +public abstract class FilterAction { + + /** + * Listens to when this FilterAction has done editing and should be ended. + */ + public interface FilterActionListener { + + void onDone(); + } + + protected final FilterStack filterStack; + protected final PhotoView photoView; + protected final ScaleWheel scaleWheel; + protected final ColorWheel colorWheel; + protected final DoodleView doodleView; + protected final TouchView touchView; + protected final RotateView rotateView; + protected final CropView cropView; + private final ViewGroup tools; + + private Toast tooltip; + private boolean pushedFilter; + private OutputCallback lastOutputCallback; + private FilterActionListener listener; + + public FilterAction(FilterStack filterStack, ViewGroup tools) { + this.filterStack = filterStack; + this.tools = tools; + + photoView = (PhotoView) tools.findViewById(R.id.photo_view); + scaleWheel = (ScaleWheel) tools.findViewById(R.id.scale_wheel); + colorWheel = (ColorWheel) tools.findViewById(R.id.color_wheel); + doodleView = (DoodleView) tools.findViewById(R.id.doodle_view); + touchView = (TouchView) tools.findViewById(R.id.touch_view); + rotateView = (RotateView) tools.findViewById(R.id.rotate_view); + cropView = (CropView) tools.findViewById(R.id.crop_view); + } + + public FilterAction(FilterStack filterStack, ViewGroup tools, int tooltipId) { + this(filterStack, tools); + + tooltip = Toast.makeText(tools.getContext(), tooltipId, Toast.LENGTH_SHORT); + } + + protected void notifyFilterChanged(Filter filter, boolean output) { + if (!pushedFilter && filter.isValid()) { + filterStack.pushFilter(filter); + pushedFilter = true; + } + if (pushedFilter && output) { + // Notify the stack to output the changed top filter. + lastOutputCallback = new OutputCallback(); + filterStack.topFilterChanged(lastOutputCallback); + } + } + + public void begin(FilterActionListener listener) { + this.listener = listener; + if (tooltip != null) { + tooltip.show(); + } + onBegin(); + } + + public void end() { + onEnd(); + + // Wait till last output callback is done before finishing. + if ((lastOutputCallback == null) || lastOutputCallback.done) { + finish(); + } else { + final SpinnerProgressDialog progressDialog = SpinnerProgressDialog.show(tools); + lastOutputCallback.runnableOnDone = new Runnable() { + + @Override + public void run() { + progressDialog.dismiss(); + finish(); + } + }; + } + } + + private void finish() { + // Close the tooltip if it's still showing. + if ((tooltip != null) && (tooltip.getView().getParent() != null)) { + tooltip.cancel(); + } + if (scaleWheel.getVisibility() == View.VISIBLE) { + scaleWheel.setOnScaleChangeListener(null); + scaleWheel.setVisibility(View.INVISIBLE); + } + if (colorWheel.getVisibility() == View.VISIBLE) { + colorWheel.setOnColorChangeListener(null); + colorWheel.setVisibility(View.INVISIBLE); + } + if (doodleView.getVisibility() == View.VISIBLE) { + doodleView.setOnDoodleChangeListener(null); + doodleView.setVisibility(View.INVISIBLE); + } + if (touchView.getVisibility() == View.VISIBLE) { + touchView.setSingleTapListener(null); + touchView.setSwipeListener(null); + touchView.setVisibility(View.INVISIBLE); + } + if (rotateView.getVisibility() == View.VISIBLE) { + rotateView.setOnAngleChangeListener(null); + rotateView.setVisibility(View.INVISIBLE); + } + if (cropView.getVisibility() == View.VISIBLE) { + cropView.setOnCropChangeListener(null); + cropView.setVisibility(View.INVISIBLE); + } + photoView.clipPhoto(null); + // Notify the listener that this action is done finishing. + listener.onDone(); + listener = null; + lastOutputCallback = null; + pushedFilter = false; + } + + /** + * Called when the action is about to begin; subclasses should creates a specific filter and + * binds the filter to necessary UI controls here. + */ + protected abstract void onBegin(); + + /** + * Called when the action is about to end; subclasses could do specific ending operations here. + */ + protected abstract void onEnd(); + + /** + * Output callback for top filter changes. + */ + private class OutputCallback implements PhotoOutputCallback { + + private boolean done; + private Runnable runnableOnDone; + + @Override + public void onReady(Photo photo) { + photoView.update(photo); + done = true; + + if (runnableOnDone != null) { + runnableOnDone.run(); + } + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/FisheyeAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/FisheyeAction.java new file mode 100644 index 0000000..efd00e6 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/FisheyeAction.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.FisheyeFilter; + +/** + * An action handling fisheye effect. + */ +public class FisheyeAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0.5f; + + public FisheyeAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final FisheyeFilter filter = new FisheyeFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setScale(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + + filter.setScale(DEFAULT_SCALE); + notifyFilterChanged(filter, true); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/FlipAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/FlipAction.java new file mode 100644 index 0000000..26402f7 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/FlipAction.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.R; +import com.android.photoeditor.animation.Rotate3DAnimation; +import com.android.photoeditor.filters.FlipFilter; + +/** + * An action handling flip effect. + */ +public class FlipAction extends FilterAction { + + private static final int ANIMATION_DURATION = 500; + + private boolean flipHorizontal; + private boolean flipVertical; + + public FlipAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools, R.string.flip_tooltip); + } + + @Override + public void onBegin() { + final FlipFilter filter = new FlipFilter(); + + touchView.setSwipeListener(new TouchView.SwipeListener() { + + @Override + public void onSwipeDown() { + setFlipAnimations(Rotate3DAnimation.Rotate.DOWN); + flipFilterVertically(filter); + } + + @Override + public void onSwipeLeft() { + setFlipAnimations(Rotate3DAnimation.Rotate.LEFT); + flipFilterHorizontally(filter); + } + + @Override + public void onSwipeRight() { + setFlipAnimations(Rotate3DAnimation.Rotate.RIGHT); + flipFilterHorizontally(filter); + } + + @Override + public void onSwipeUp() { + setFlipAnimations(Rotate3DAnimation.Rotate.UP); + flipFilterVertically(filter); + } + }); + touchView.setVisibility(View.VISIBLE); + + flipHorizontal = false; + flipVertical = false; + setFlipAnimations(Rotate3DAnimation.Rotate.RIGHT); + flipFilterHorizontally(filter); + } + + @Override + public void onEnd() { + } + + private void setFlipAnimations(Rotate3DAnimation.Rotate rotate) { + photoView.setTransitionAnimations( + Rotate3DAnimation.getFlipAnimations(rotate, ANIMATION_DURATION)); + } + + private void flipFilterHorizontally(final FlipFilter filter) { + flipHorizontal = !flipHorizontal; + filter.setFlip(flipHorizontal, flipVertical); + notifyFilterChanged(filter, true); + } + + private void flipFilterVertically(final FlipFilter filter) { + flipVertical = !flipVertical; + filter.setFlip(flipHorizontal, flipVertical); + notifyFilterChanged(filter, true); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/GrainAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/GrainAction.java new file mode 100644 index 0000000..a841d5d --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/GrainAction.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.GrainFilter; + +/** + * An action handling the film-grain effect. + */ +public class GrainAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0.5f; + + public GrainAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final GrainFilter filter = new GrainFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setScale(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + + filter.setScale(DEFAULT_SCALE); + notifyFilterChanged(filter, true); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/GrayscaleAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/GrayscaleAction.java new file mode 100644 index 0000000..aa13f58 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/GrayscaleAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.GrayscaleFilter; + +/** + * An action handling grayscale effect. + */ +public class GrayscaleAction extends FilterAction { + + public GrayscaleAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new GrayscaleFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/HighlightAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/HighlightAction.java new file mode 100644 index 0000000..a5cc9d9 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/HighlightAction.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.HighlightFilter; + +/** + * An action handling highlight effect. + */ +public class HighlightAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0f; + + public HighlightAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final HighlightFilter filter = new HighlightFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setHighlight(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/LomoishAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/LomoishAction.java new file mode 100644 index 0000000..0642023 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/LomoishAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.LomoishFilter; + +/** + * An action handling the preset "Lomo-ish" effect. + */ +public class LomoishAction extends FilterAction { + + public LomoishAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new LomoishFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/NegativeAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/NegativeAction.java new file mode 100644 index 0000000..421d5cc --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/NegativeAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.NegativeFilter; + +/** + * An action handling negative effect. + */ +public class NegativeAction extends FilterAction { + + public NegativeAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new NegativeFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/PosterizeAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/PosterizeAction.java new file mode 100644 index 0000000..e1c0528 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/PosterizeAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.PosterizeFilter; + +/** + * An action handling the "Posterize" effect. + */ +public class PosterizeAction extends FilterAction { + + public PosterizeAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new PosterizeFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/RedEyeAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/RedEyeAction.java new file mode 100644 index 0000000..9a36adb --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/RedEyeAction.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.R; +import com.android.photoeditor.filters.RedEyeFilter; + +/** + * An action handling red-eye removal. + */ +public class RedEyeAction extends FilterAction { + + public RedEyeAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools, R.string.redeye_tooltip); + } + + @Override + public void onBegin() { + final RedEyeFilter filter = new RedEyeFilter(); + + touchView.setSingleTapListener(new TouchView.SingleTapListener() { + + @Override + public void onSingleTap(float x, float y) { + filter.addRedEyePosition(photoView.mapPhotoPoint(x, y)); + notifyFilterChanged(filter, true); + } + }); + touchView.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/RotateAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/RotateAction.java new file mode 100644 index 0000000..a04f9d3 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/RotateAction.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.R; +import com.android.photoeditor.RectUtils; +import com.android.photoeditor.filters.RotateFilter; + +/** + * An action handling rotate effect. + */ +public class RotateAction extends FilterAction { + + private static final float DEFAULT_ANGLE = 0.0f; + private static final float DEFAULT_ROTATE_SPAN = 360.0f; + + private RotateFilter filter; + private float rotateDegrees; + + public RotateAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools, R.string.rotate_tooltip); + } + + @Override + public void onBegin() { + filter = new RotateFilter(); + rotateDegrees = 0; + + final Matrix matrix = new Matrix(); + final RectF rotateBounds = new RectF(); + final RectF photoBounds = photoView.getPhotoBounds(); + + // Directly transform photo-view instead of waiting for top-filter output callback. + rotateView.setOnAngleChangeListener(new RotateView.OnRotateChangeListener() { + + @Override + public void onAngleChanged(float degrees, boolean fromUser){ + if (fromUser) { + rotateDegrees = degrees; + filter.setAngle(degrees); + notifyFilterChanged(filter, false); + transformPhotoView(degrees); + } + } + + @Override + public void onStartTrackingTouch() { + // no-op + } + + @Override + public void onStopTrackingTouch() { + if (roundFilterRotationDegrees()) { + notifyFilterChanged(filter, false); + transformPhotoView(rotateDegrees); + rotateView.setRotatedAngle(rotateDegrees); + } + } + + private void transformPhotoView(float degrees) { + matrix.reset(); + rotateBounds.set(photoBounds); + RectUtils.postRotateMatrix(degrees, rotateBounds, matrix); + float scale = RectUtils.getDisplayScale(rotateBounds, photoView); + matrix.postScale(scale, scale); + photoView.transformDisplay(matrix); + } + }); + rotateView.setGridBounds(null); + rotateView.setRotatedAngle(DEFAULT_ANGLE); + rotateView.setRotateSpan(DEFAULT_ROTATE_SPAN); + rotateView.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + // Round the current rotation degrees in case rotation tracking has not stopped yet. + roundFilterRotationDegrees(); + notifyFilterChanged(filter, true); + } + + /** + * Rounds filter rotation degrees to multiples of 90 degrees. + * + * @return true if the rotation degrees has been changed. + */ + private boolean roundFilterRotationDegrees() { + if (rotateDegrees % 90 != 0) { + rotateDegrees = Math.round(rotateDegrees / 90) * 90; + filter.setAngle(rotateDegrees); + return true; + } + return false; + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/RotateView.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/RotateView.java new file mode 100644 index 0000000..b0cea16 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/RotateView.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.DashPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +/** + * View that shows grids and handles touch-events to adjust angle of rotation. + */ +class RotateView extends View { + + /** + * Listens to rotate changes. + */ + public interface OnRotateChangeListener { + + void onAngleChanged(float degrees, boolean fromUser); + + void onStartTrackingTouch(); + + void onStopTrackingTouch(); + } + + // All angles used are defined between PI and -PI. + private static final float MATH_PI = (float) Math.PI; + private static final float MATH_HALF_PI = MATH_PI / 2; + private static final float RADIAN_TO_DEGREE = 180f / MATH_PI; + + private final Paint dashStrokePaint; + private final Path grids = new Path(); + private final Path referenceLine = new Path(); + private final RectF referenceLineBounds = new RectF(); + + private OnRotateChangeListener listener; + private int centerX; + private int centerY; + private float maxRotatedAngle; + private float minRotatedAngle; + private float currentRotatedAngle; + private float lastRotatedAngle; + private float touchStartAngle; + + public RotateView(Context context, AttributeSet attrs) { + super(context, attrs); + + dashStrokePaint = new Paint(); + dashStrokePaint.setAntiAlias(true); + dashStrokePaint.setStyle(Paint.Style.STROKE); + dashStrokePaint.setPathEffect(new DashPathEffect(new float[] {15.0f, 5.0f}, 1.0f)); + } + + public void setRotatedAngle(float degrees) { + currentRotatedAngle = -degrees / RADIAN_TO_DEGREE; + notifyAngleChange(false); + } + + /** + * Sets allowed degrees for rotation span before rotating the view. + */ + public void setRotateSpan(float degrees) { + if (degrees >= 360f) { + maxRotatedAngle = Float.POSITIVE_INFINITY; + } else { + maxRotatedAngle = (degrees / RADIAN_TO_DEGREE) / 2; + } + minRotatedAngle = -maxRotatedAngle; + } + + /** + * Sets grid bounds to be drawn or null to hide grids right before the view is visible. + */ + public void setGridBounds(RectF bounds) { + grids.reset(); + referenceLine.reset(); + if (bounds != null) { + float delta = bounds.width() / 4.0f; + for (float x = bounds.left + delta; x < bounds.right; x += delta) { + grids.moveTo(x, bounds.top); + grids.lineTo(x, bounds.bottom); + } + delta = bounds.height() / 4.0f; + for (float y = bounds.top + delta; y < bounds.bottom; y += delta) { + grids.moveTo(bounds.left, y); + grids.lineTo(bounds.right, y); + } + + // Make reference line long enough to cross the bounds diagonally after being rotated. + referenceLineBounds.set(bounds); + float radius = (float) Math.hypot(centerX, centerY); + delta = radius - centerX; + referenceLine.moveTo(-delta, centerY); + referenceLine.lineTo(getWidth() + delta, centerY); + + delta = radius - centerY; + referenceLine.moveTo(centerX, -delta); + referenceLine.lineTo(centerX, getHeight() + delta); + } + invalidate(); + } + + public void setOnAngleChangeListener(OnRotateChangeListener listener) { + this.listener = listener; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + centerX = w / 2; + centerY = h / 2; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (!grids.isEmpty()) { + dashStrokePaint.setStrokeWidth(2f); + dashStrokePaint.setColor(0x99CCCCCC); + canvas.drawPath(grids, dashStrokePaint); + } + + if (!referenceLine.isEmpty()) { + dashStrokePaint.setStrokeWidth(2f); + dashStrokePaint.setColor(0x99FFCC77); + canvas.save(); + canvas.clipRect(referenceLineBounds); + canvas.rotate(-currentRotatedAngle * RADIAN_TO_DEGREE, centerX, centerY); + canvas.drawPath(referenceLine, dashStrokePaint); + canvas.restore(); + } + } + + private float calculateAngle(MotionEvent ev) { + float x = ev.getX() - centerX; + float y = centerY - ev.getY(); + + float angle; + if (x == 0) { + angle = (y >= 0) ? MATH_HALF_PI : -MATH_HALF_PI; + } else { + angle = (float) Math.atan(y / x); + } + + if ((angle >= 0) && (x < 0)) { + angle = angle - MATH_PI; + } else if ((angle < 0) && (x < 0)) { + angle = MATH_PI + angle; + } + return angle; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + + if (isEnabled()) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + lastRotatedAngle = currentRotatedAngle; + touchStartAngle = calculateAngle(ev); + + if (listener != null) { + listener.onStartTrackingTouch(); + } + break; + + case MotionEvent.ACTION_MOVE: + float touchAngle = calculateAngle(ev); + float rotatedAngle = touchAngle - touchStartAngle + lastRotatedAngle; + + if ((rotatedAngle > maxRotatedAngle) || (rotatedAngle < minRotatedAngle)) { + // Angles are out of range; restart rotating. + // TODO: Fix discontinuity around boundary. + lastRotatedAngle = currentRotatedAngle; + touchStartAngle = touchAngle; + } else { + currentRotatedAngle = rotatedAngle; + notifyAngleChange(true); + invalidate(); + } + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + if (listener != null) { + listener.onStopTrackingTouch(); + } + break; + } + } + return true; + } + + private void notifyAngleChange(boolean fromUser) { + if (listener != null) { + listener.onAngleChanged(-currentRotatedAngle * RADIAN_TO_DEGREE, fromUser); + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/SaturationAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/SaturationAction.java new file mode 100644 index 0000000..aad4178 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/SaturationAction.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.SaturationFilter; + +/** + * An action handling saturation effect. + */ +public class SaturationAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0.5f; + + public SaturationAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final SaturationFilter filter = new SaturationFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setSaturation(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/ScaleWheel.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/ScaleWheel.java new file mode 100644 index 0000000..fd25c87 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/ScaleWheel.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AnimationUtils; + +import com.android.photoeditor.R; + +/** + * Wheel that has a draggable thumb to set and get the normalized scale value from 0 to 1. + */ +class ScaleWheel extends View { + + /** + * Listens to scale changes. + */ + public interface OnScaleChangeListener { + + void onProgressChanged(float progress, boolean fromUser); + } + + private static final float MATH_PI = (float) Math.PI; + private static final float MATH_HALF_PI = MATH_PI / 2; + + // Angles are defined between PI and -PI. + private static final float ANGLE_SPANNED = MATH_PI * 4 / 3; + private static final float ANGLE_BEGIN = ANGLE_SPANNED / 2.0f; + + private static final float THUMB_RADIUS_RATIO = 0.363f; + private static final float INNER_RADIUS_RATIO = 0.24f; + + private final Drawable thumb; + private final Drawable background; + private final int thumbSize; + private final Paint circlePaint; + private final int maxProgress; + private final float radiantInterval; + private int thumbRadius; + private int innerRadius; + private int centerXY; + private float angle; + private int progress; + private boolean dragThumb; + private OnScaleChangeListener listener; + + public ScaleWheel(Context context, AttributeSet attrs) { + super(context, attrs); + + Resources resources = context.getResources(); + thumbSize = (int) resources.getDimension(R.dimen.wheel_thumb_size); + + // Set the maximum progress and compute the radiant interval between progress values. + maxProgress = 100; + radiantInterval = ANGLE_SPANNED / maxProgress; + + thumb = resources.getDrawable(R.drawable.wheel_knot_selector); + background = resources.getDrawable(R.drawable.scale_wheel_background); + background.setAlpha(160); + + circlePaint = new Paint(); + circlePaint.setAntiAlias(true); + circlePaint.setColor(resources.getColor(R.color.scale_wheel_interior_color)); + } + + public void setProgress(float progress) { + if (updateProgress((int) (progress * maxProgress), false)) { + updateThumbPositionByProgress(); + } + } + + public void setOnScaleChangeListener(OnScaleChangeListener listener) { + this.listener = listener; + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + + startAnimation(AnimationUtils.loadAnimation(getContext(), + (visibility == VISIBLE) ? R.anim.wheel_show : R.anim.wheel_hide)); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + int wheelSize = Math.min(w, h); + thumbRadius = (int) (wheelSize * THUMB_RADIUS_RATIO); + innerRadius = (int) (wheelSize * INNER_RADIUS_RATIO); + + // The wheel would be centered at (centerXY, centerXY) and have outer-radius centerXY. + centerXY = wheelSize / 2; + updateThumbPositionByProgress(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + background.setBounds(0, 0, getWidth(), getHeight()); + background.draw(canvas); + + int thumbX = (int) (thumbRadius * Math.cos(angle) + centerXY); + int thumbY = (int) (centerXY - thumbRadius * Math.sin(angle)); + int halfSize = thumbSize / 2; + thumb.setBounds(thumbX - halfSize, thumbY - halfSize, thumbX + halfSize, thumbY + halfSize); + thumb.draw(canvas); + + float radius = (progress * innerRadius) / maxProgress; + canvas.drawCircle(centerXY, centerXY, radius, circlePaint); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + + if (isEnabled()) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + updateThumbState( + isHittingThumbArea(ev.getX() - centerXY, centerXY - ev.getY())); + break; + + case MotionEvent.ACTION_MOVE: + float x = ev.getX() - centerXY; + float y = centerXY - ev.getY(); + if (!dragThumb && !updateThumbState(isHittingThumbArea(x, y))) { + // The thumb wasn't dragged and isn't being dragged, either. + break; + } + + if (updateAngle(x, y)) { + int progress = (int) ((ANGLE_BEGIN - angle) / radiantInterval); + if (updateProgress(progress, true)) { + invalidate(); + } + } + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + updateThumbState(false); + break; + } + } + return true; + } + + private boolean isHittingThumbArea(float x, float y) { + double radius = Math.sqrt((x * x) + (y * y)); + return (radius > innerRadius) && (radius < centerXY); + } + + private boolean updateAngle(float x, float y) { + float angle; + if (x == 0) { + angle = (y >= 0) ? MATH_HALF_PI : -MATH_HALF_PI; + } else { + angle = (float) Math.atan(y / x); + } + + if ((angle >= 0) && (x < 0)) { + angle = angle - MATH_PI; + } else if ((angle < 0) && (x < 0)) { + angle = MATH_PI + angle; + } + + if ((angle > ANGLE_BEGIN) || (angle <= ANGLE_BEGIN - ANGLE_SPANNED)) { + return false; + } + + this.angle = angle; + return true; + } + + private boolean updateProgress(int progress, boolean fromUser) { + if ((this.progress != progress) && (progress >= 0) && (progress <= maxProgress)) { + this.progress = progress; + + if (listener != null) { + listener.onProgressChanged((float) progress / maxProgress, fromUser); + } + return true; + } + return false; + } + + private void updateThumbPositionByProgress() { + angle = ANGLE_BEGIN - progress * radiantInterval; + invalidate(); + } + + private boolean updateThumbState(boolean dragThumb) { + if (this.dragThumb == dragThumb) { + // The state hasn't been changed; no need for updates. + return false; + } + + this.dragThumb = dragThumb; + thumb.setState(dragThumb ? PRESSED_ENABLED_STATE_SET : ENABLED_STATE_SET); + invalidate(); + return true; + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/SepiaAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/SepiaAction.java new file mode 100644 index 0000000..26eea2e --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/SepiaAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.SepiaFilter; + +/** + * An action handling sepia effect. + */ +public class SepiaAction extends FilterAction { + + public SepiaAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new SepiaFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/ShadowAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/ShadowAction.java new file mode 100644 index 0000000..b159ba5 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/ShadowAction.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.ShadowFilter; + +/** + * An action handling shadow effect. + */ +public class ShadowAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0f; + + public ShadowAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final ShadowFilter filter = new ShadowFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setShadow(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/SharpenAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/SharpenAction.java new file mode 100644 index 0000000..1c0542f --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/SharpenAction.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.SharpenFilter; + +/** + * An action handling sharpen effect. + */ +public class SharpenAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0.5f; + + public SharpenAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final SharpenFilter filter = new SharpenFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setSharpen(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + + filter.setSharpen(DEFAULT_SCALE); + notifyFilterChanged(filter, true); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/SoftFocusAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/SoftFocusAction.java new file mode 100644 index 0000000..34dc201 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/SoftFocusAction.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.SoftFocusFilter; + +/** + * An action handling soft focus effect. + */ +public class SoftFocusAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0f; + + public SoftFocusAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final SoftFocusFilter filter = new SoftFocusFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setSoftFocus(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/StraightenAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/StraightenAction.java new file mode 100644 index 0000000..0e84d9b --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/StraightenAction.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.R; +import com.android.photoeditor.RectUtils; +import com.android.photoeditor.filters.StraightenFilter; + +/** + * An action handling straighten effect. + */ +public class StraightenAction extends FilterAction { + + private static final float DEFAULT_ANGLE = 0.0f; + private static final float DEFAULT_ROTATE_SPAN = 60.0f; + + private StraightenFilter filter; + + public StraightenAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools, R.string.straighten_tooltip); + } + + @Override + public void onBegin() { + filter = new StraightenFilter(); + + final Matrix matrix = new Matrix(); + final RectF photoBounds = photoView.getPhotoBounds(); + final float displayScale = RectUtils.getDisplayScale(photoBounds, photoView); + + RectF displayBounds = photoView.getPhotoDisplayBounds(); + photoView.clipPhoto(displayBounds); + + // Directly transform photo-view instead of waiting for top-filter output callback. + rotateView.setOnAngleChangeListener(new RotateView.OnRotateChangeListener() { + + @Override + public void onAngleChanged(float angle, boolean fromUser){ + if (fromUser) { + filter.setAngle(angle); + notifyFilterChanged(filter, false); + RectUtils.getStraightenMatrix(photoBounds, angle, matrix); + matrix.postScale(displayScale, displayScale); + photoView.transformDisplay(matrix); + } + } + + @Override + public void onStartTrackingTouch() { + // no-op + } + + @Override + public void onStopTrackingTouch() { + // no-op + } + }); + rotateView.setGridBounds(displayBounds); + rotateView.setRotatedAngle(DEFAULT_ANGLE); + rotateView.setRotateSpan(DEFAULT_ROTATE_SPAN); + rotateView.setVisibility(View.VISIBLE); + } + + @Override + public void onEnd() { + notifyFilterChanged(filter, true); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/TintAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/TintAction.java new file mode 100644 index 0000000..23cca2b --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/TintAction.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.TintFilter; + +/** + * An action handling tint effect. + */ +public class TintAction extends FilterAction { + + private static final int DEFAULT_COLOR_INDEX = 13; + + public TintAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final TintFilter filter = new TintFilter(); + + colorWheel.setOnColorChangeListener(new ColorWheel.OnColorChangeListener() { + + @Override + public void onColorChanged(int color, boolean fromUser){ + if (fromUser) { + filter.setTint(color); + notifyFilterChanged(filter, true); + } + } + }); + // Tint photo with the default color. + colorWheel.setColorIndex(DEFAULT_COLOR_INDEX); + colorWheel.setVisibility(View.VISIBLE); + + filter.setTint(colorWheel.getColor()); + notifyFilterChanged(filter, true); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/TouchView.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/TouchView.java new file mode 100644 index 0000000..5c000fb --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/TouchView.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; + +/** + * A view that detects user gestures and touch motions. + */ +class TouchView extends View { + + /** + * Listener of swipes. + */ + public interface SwipeListener { + + void onSwipeLeft(); + + void onSwipeRight(); + + void onSwipeUp(); + + void onSwipeDown(); + } + + /** + * Listener of single tap confirmed (click). + */ + public interface SingleTapListener { + + void onSingleTap(float x, float y); + } + + private final GestureDetector gestureDetector; + + private SwipeListener swipeListener; + private SingleTapListener singleTapListener; + + public TouchView(Context context, AttributeSet attrs) { + super(context, attrs); + + final int swipeThreshold = (int) (500 * getResources().getDisplayMetrics().density); + gestureDetector = new GestureDetector( + context, new GestureDetector.SimpleOnGestureListener() { + + @Override + public boolean onDown(MotionEvent e) { + // GestureDetector onTouchEvent returns true for fling events only when their + // preceding down events are consumed. + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (singleTapListener != null) { + singleTapListener.onSingleTap(e.getX(), e.getY()); + } + return true; + } + + @Override + public boolean onFling( + MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) { + if (swipeListener != null) { + float absX = Math.abs(velocityX); + float absY = Math.abs(velocityY); + float deltaX = me2.getX() - me1.getX(); + float deltaY = me2.getY() - me1.getY(); + int travelX = getWidth() / 4; + int travelY = getHeight() / 4; + if (velocityX > swipeThreshold && absY < absX && deltaX > travelX) { + swipeListener.onSwipeRight(); + } else if (velocityX < -swipeThreshold && absY < absX && deltaX < -travelX) { + swipeListener.onSwipeLeft(); + } else if (velocityY < -swipeThreshold && absX < absY && deltaY < -travelY) { + swipeListener.onSwipeUp(); + } else if (velocityY > swipeThreshold && absX < absY / 2 && deltaY > travelY) { + swipeListener.onSwipeDown(); + } + } + return true; + } + }); + gestureDetector.setIsLongpressEnabled(false); + } + + public void setSwipeListener(SwipeListener listener) { + swipeListener = listener; + } + + public void setSingleTapListener(SingleTapListener listener) { + singleTapListener = listener; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return isEnabled() && gestureDetector.onTouchEvent(event); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/VignetteAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/VignetteAction.java new file mode 100644 index 0000000..6b54142 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/VignetteAction.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.VignetteFilter; + +/** + * An action handling vignette effect. + */ +public class VignetteAction extends FilterAction { + + private static final float DEFAULT_SCALE = 0.5f; + + public VignetteAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + final VignetteFilter filter = new VignetteFilter(); + + scaleWheel.setOnScaleChangeListener(new ScaleWheel.OnScaleChangeListener() { + + @Override + public void onProgressChanged(float progress, boolean fromUser) { + if (fromUser) { + filter.setScale(progress); + notifyFilterChanged(filter, true); + } + } + }); + scaleWheel.setProgress(DEFAULT_SCALE); + scaleWheel.setVisibility(View.VISIBLE); + + filter.setScale(DEFAULT_SCALE); + notifyFilterChanged(filter, true); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/actions/WarmifyAction.java b/samples/PhotoEditor/src/com/android/photoeditor/actions/WarmifyAction.java new file mode 100644 index 0000000..002e107 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/actions/WarmifyAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.actions; + +import android.view.ViewGroup; + +import com.android.photoeditor.FilterStack; +import com.android.photoeditor.filters.WarmifyFilter; + +/** + * An action handling warmify effect. + */ +public class WarmifyAction extends FilterAction { + + public WarmifyAction(FilterStack filterStack, ViewGroup tools) { + super(filterStack, tools); + } + + @Override + public void onBegin() { + notifyFilterChanged(new WarmifyFilter(), true); + end(); + } + + @Override + public void onEnd() { + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/animation/AnimationPair.java b/samples/PhotoEditor/src/com/android/photoeditor/animation/AnimationPair.java new file mode 100644 index 0000000..153855c --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/animation/AnimationPair.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.animation; + +import android.view.animation.Animation; + +/** + * A pair of animations that will be played sequentially, e.g. fade-out and then fade-in. + */ +public class AnimationPair { + + private final Animation first; + private final Animation second; + + AnimationPair(Animation first, Animation second) { + this.first = first; + this.second = second; + } + + public Animation first() { + return first; + } + + public Animation second() { + return second; + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/animation/FadeAnimation.java b/samples/PhotoEditor/src/com/android/photoeditor/animation/FadeAnimation.java new file mode 100644 index 0000000..45a7c33 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/animation/FadeAnimation.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.animation; + +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; + +/** + * Fading animation that either fades in or out the view by alpha animations. + */ +public class FadeAnimation { + + /** + * Gets animations that fade out and then fade in the view. + */ + public static AnimationPair getFadeOutInAnimations(int duration) { + Animation fadeOut = new AlphaAnimation(1.0f, 0.5f); + Animation fadeIn = new AlphaAnimation(0.5f, 1.0f); + fadeOut.setDuration(duration); + fadeIn.setDuration(duration); + + return new AnimationPair(fadeOut, fadeIn); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/animation/Rotate3DAnimation.java b/samples/PhotoEditor/src/com/android/photoeditor/animation/Rotate3DAnimation.java new file mode 100644 index 0000000..01e5a92 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/animation/Rotate3DAnimation.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.animation; + +import android.graphics.Camera; +import android.graphics.Matrix; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Transformation; + +/** + * Rotation animation that rotates a 2D view 90 degrees on either X or Y axis in 3D space. The + * rotation is performed around the view center point by its defined rotation direction and position + * it will start from or end to. The rotation duration can be specified as well as whether the + * rotation should be accelerated or decelerated in time. + */ +public class Rotate3DAnimation extends Animation { + + public enum Rotate { + UP, DOWN, LEFT, RIGHT + } + + private enum Angle { + FROM_DEGREES_0, TO_DEGREES_0 + } + + private static final float DEPTH_Z = 250.0f; + private static final float ROTATE_DEGREES = 90f; + + private final Rotate rotate; + private final Angle angle; + private final int duration; + private final boolean accelerate; + + private Camera camera; + private float centerX; + private float centerY; + private float fromDegrees; + private float toDegrees; + + /** + * Gets animations that flip the view by 3D rotations. + */ + public static AnimationPair getFlipAnimations(Rotate rotate, int duration) { + return new AnimationPair( + new Rotate3DAnimation(rotate, Angle.FROM_DEGREES_0, duration, true), + new Rotate3DAnimation(rotate, Angle.TO_DEGREES_0, duration, false)); + } + + private Rotate3DAnimation(Rotate rotate, Angle angle, int duration, boolean accelerate) { + this.rotate = rotate; + this.angle = angle; + this.duration = duration; + this.accelerate = accelerate; + } + + @Override + public void initialize(int width, int height, int parentWidth, int parentHeight) { + super.initialize(width, height, parentWidth, parentHeight); + super.setDuration(duration); + super.setInterpolator( + accelerate ? new AccelerateInterpolator() : new DecelerateInterpolator()); + + camera = new Camera(); + centerX = width / 2.0f; + centerY = height / 2.0f; + + if (angle == Angle.FROM_DEGREES_0) { + fromDegrees = 0; + + switch (rotate) { + case RIGHT: + case UP: + toDegrees = ROTATE_DEGREES; + break; + + case LEFT: + case DOWN: + toDegrees = -ROTATE_DEGREES; + break; + } + } else if (angle == Angle.TO_DEGREES_0) { + toDegrees = 0; + + switch (rotate) { + case RIGHT: + case UP: + fromDegrees = -ROTATE_DEGREES; + break; + + case LEFT: + case DOWN: + fromDegrees = ROTATE_DEGREES; + break; + } + } + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + camera.save(); + + if (angle == Angle.FROM_DEGREES_0) { + camera.translate(0.0f, 0.0f, DEPTH_Z * interpolatedTime); + } else if (angle == Angle.TO_DEGREES_0) { + camera.translate(0.0f, 0.0f, DEPTH_Z * (1.0f - interpolatedTime)); + } + + float degrees = fromDegrees + ((toDegrees - fromDegrees) * interpolatedTime); + switch (rotate) { + case RIGHT: + case LEFT: + camera.rotateY(degrees); + break; + + case UP: + case DOWN: + camera.rotateX(degrees); + break; + } + + final Matrix matrix = t.getMatrix(); + camera.getMatrix(matrix); + camera.restore(); + + matrix.preTranslate(-centerX, -centerY); + matrix.postTranslate(centerX, centerY); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/AutoFixFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/AutoFixFilter.java new file mode 100644 index 0000000..027f090 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/AutoFixFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Auto-fix filter applied to the image. + */ +public class AutoFixFilter extends Filter { + + private float scale; + + /** + * Sets the auto-fix level. + * + * @param scale ranges from 0 to 1. + */ + public void setScale(float scale) { + this.scale = scale; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeHEQ(src.bitmap(), dst.bitmap(), scale); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/ColorTemperatureFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/ColorTemperatureFilter.java new file mode 100644 index 0000000..4fb00af --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/ColorTemperatureFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Color temperature filter applied to the image. + */ +public class ColorTemperatureFilter extends Filter { + + private float colorTemperature; + + /** + * Sets the color temperature level. + * + * @param scale ranges from 0 to 1. + */ + public void setColorTemperature(float scale) { + this.colorTemperature = (scale - 0.5f); + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeColorTemp(src.bitmap(), dst.bitmap(), colorTemperature); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/CropFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/CropFilter.java new file mode 100644 index 0000000..5795bbb --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/CropFilter.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import android.graphics.RectF; + +import com.android.photoeditor.Photo; + +/** + * Crop filter applied to the image. + */ +public class CropFilter extends Filter { + + private RectF bounds; + + /** + * The coordinates used here should range from 0 to 1. + */ + public void setCropBounds(RectF bounds) { + this.bounds = bounds; + validate(); + } + + public void process(Photo src, Photo dst) { + ImageUtils.nativeCopy(src.bitmap(), dst.bitmap()); + dst.crop((int) (src.width() * bounds.left), (int) (src.height() * bounds.top), + (int) (src.width() * bounds.width()), (int) (src.height() * bounds.height())); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/CrossProcessFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/CrossProcessFilter.java new file mode 100644 index 0000000..943f2a8 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/CrossProcessFilter.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Cross-process filter applied to the image. + */ +public class CrossProcessFilter extends Filter { + + public CrossProcessFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeCrossProcess(src.bitmap(), dst.bitmap()); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/DocumentaryFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/DocumentaryFilter.java new file mode 100644 index 0000000..0a0c097 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/DocumentaryFilter.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Preset "Documentary" applied to the image. + */ +public class DocumentaryFilter extends Filter { + + public DocumentaryFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeWhiteBlack(src.bitmap(), dst.bitmap(), 0.5f, 0f); + ImageUtils.nativeGrayscale(dst.bitmap(), dst.bitmap(), 1.0f); + ImageUtils.nativeVignetting(dst.bitmap(), dst.bitmap(), 0.83f); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/DoodleFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/DoodleFilter.java new file mode 100644 index 0000000..365a737 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/DoodleFilter.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; + +import com.android.photoeditor.actions.ColorPath; +import com.android.photoeditor.Photo; + +import java.util.Vector; + +/** + * Doodle filter applied to the image. + */ +public class DoodleFilter extends Filter { + + private final Vector<ColorPath> doodles = new Vector<ColorPath>(); + private final Paint paint = ColorPath.createPaint(); + private final Canvas canvas = new Canvas(); + + public void addPath(int color) { + // Remove last empty path before adding a new one. + if (!doodles.isEmpty() && doodles.lastElement().path().isEmpty()) { + doodles.remove(doodles.size() - 1); + } + doodles.add(new ColorPath(color, new Path())); + } + + public synchronized void updateLastPath(Path path) { + if (!doodles.isEmpty()) { + doodles.lastElement().path().set(path); + validate(); + } + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeCopy(src.bitmap(), dst.bitmap()); + + if (!doodles.isEmpty()) { + canvas.setBitmap(dst.bitmap()); + for (ColorPath doodle : doodles) { + doodle.draw(canvas, paint); + } + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/DuotoneFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/DuotoneFilter.java new file mode 100644 index 0000000..e56f2d5 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/DuotoneFilter.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Duotone filter applied to the image. + */ +public class DuotoneFilter extends Filter { + + private int firstColor; + private int secondColor; + + public void setDuotone(int firstColor, int secondColor) { + this.firstColor = firstColor; + this.secondColor = secondColor; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeDuotone(src.bitmap(), dst.bitmap(), firstColor, secondColor); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/FillLightFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/FillLightFilter.java new file mode 100644 index 0000000..547f082 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/FillLightFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Fill-light filter applied to the image. + */ +public class FillLightFilter extends Filter { + + private float backlight; + + /** + * Sets the backlight level. + * + * @param backlight ranges from 0 to 1. + */ + public void setBacklight(float backlight) { + this.backlight = backlight; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeBacklight(src.bitmap(), dst.bitmap(), backlight); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/Filter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/Filter.java new file mode 100644 index 0000000..11afd51 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/Filter.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Image filter for photo editing. + */ +public abstract class Filter { + + private boolean isValid; + + protected void validate() { + isValid = true; + } + + /** + * Some filters, e.g. lighting filters, are initially invalid until set up with parameters while + * others, e.g. sepia or flip filters, are initially valid without parameters. + */ + public boolean isValid() { + return isValid; + } + + /** + * Processes the source bitmap and matrix and output the destination bitmap and matrix. + * + * @param src source photo as the input. + * @param dst destination photo having the same dimension as source photo as the output. + */ + public abstract void process(Photo src, Photo dst); +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/FisheyeFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/FisheyeFilter.java new file mode 100644 index 0000000..f60918a --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/FisheyeFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Fisheye filter applied to the image. + */ +public class FisheyeFilter extends Filter { + + private float scale; + + /** + * Sets the fisheye distortion level. + * + * @param scale ranges from 0 to 1. + */ + public void setScale(float scale) { + this.scale = scale; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeFisheye(src.bitmap(), dst.bitmap(), 0.5f, 0.5f, scale); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/FlipFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/FlipFilter.java new file mode 100644 index 0000000..291afa2 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/FlipFilter.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Flip filter applied to the image. + */ +public class FlipFilter extends Filter { + + private boolean flipHorizontal; + private boolean flipVertical; + + public void setFlip(boolean flipHorizontal, boolean flipVertical) { + this.flipHorizontal = flipHorizontal; + this.flipVertical = flipVertical; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + if (flipHorizontal && flipVertical) { + ImageUtils.nativeFlipBoth(src.bitmap(), dst.bitmap()); + } else if (flipHorizontal) { + ImageUtils.nativeFlipHorizontal(src.bitmap(), dst.bitmap()); + } else if (flipVertical){ + ImageUtils.nativeFlipVertical(src.bitmap(), dst.bitmap()); + } else { + ImageUtils.nativeCopy(src.bitmap(), dst.bitmap()); + } + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/GrainFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/GrainFilter.java new file mode 100644 index 0000000..8ee81d2 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/GrainFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Film grain filter applied to the image. + */ +public class GrainFilter extends Filter { + + private float scale; + + /** + * Set the grain noise level. + * + * @param scale ranges from 0 to 1. + */ + public void setScale(float scale) { + this.scale = scale; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeGrain(src.bitmap(), dst.bitmap(), scale); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/GrayscaleFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/GrayscaleFilter.java new file mode 100644 index 0000000..164aaa0 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/GrayscaleFilter.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Grayscale filter applied to the image. + */ +public class GrayscaleFilter extends Filter { + + public GrayscaleFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeGrayscale(src.bitmap(), dst.bitmap(), 1.0f); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/HighlightFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/HighlightFilter.java new file mode 100644 index 0000000..22efbe1 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/HighlightFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Highlight filter applied to the image. + */ +public class HighlightFilter extends Filter { + + private float white; + + /** + * Sets the highlight level. + * + * @param highlight ranges from 0 to 1. + */ + public void setHighlight(float highlight) { + white = 1f - highlight * 0.5f; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeWhiteBlack(src.bitmap(), dst.bitmap(), white, 0f); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/ImageUtils.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/ImageUtils.java new file mode 100644 index 0000000..e37a30f --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/ImageUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import android.graphics.Bitmap; +import android.graphics.PointF; + + +/** + * Image utilities that calls to JNI methods for image processing. + */ +public class ImageUtils { + + static { + System.loadLibrary("jni_photoeditor"); + } + + public static native boolean init(byte[] pgm, int pgmLength); + + public static native void nativeBacklight(Bitmap src, Bitmap dst, float backlight); + public static native void nativeBlur(Bitmap src, Bitmap dst, float scale); + public static native void nativeColorTemp(Bitmap src, Bitmap dst, float scale); + public static native void nativeCopy(Bitmap src, Bitmap dst); + public static native void nativeCrossProcess(Bitmap src, Bitmap dst); + public static native void nativeDuotone(Bitmap src, Bitmap dst, int firstColor, + int secondColor); + public static native void nativeFisheye(Bitmap src, Bitmap dst, float focusX, + float focusY, float scale); + public static native void nativeFlipBoth(Bitmap src, Bitmap dst); + public static native void nativeFlipHorizontal(Bitmap src, Bitmap dst); + public static native void nativeFlipVertical(Bitmap src, Bitmap dst); + public static native void nativeGrain(Bitmap src, Bitmap dst, float scale); + public static native void nativeGrayscale(Bitmap src, Bitmap dst, float scale); + public static native void nativeHEQ(Bitmap src, Bitmap dst, float scale); + public static native void nativeNegative(Bitmap src, Bitmap dst); + public static native void nativeQuantize(Bitmap src, Bitmap dst); + public static native void nativeRedEye(Bitmap src, Bitmap dst, PointF[] redeyes, + float radius, float intensity); + public static native void nativeSaturation(Bitmap src, Bitmap dst, float scale); + public static native void nativeSepia(Bitmap src, Bitmap dst); + public static native void nativeSharpen(Bitmap src, Bitmap dst, float scale); + public static native void nativeTint(Bitmap src, Bitmap dst, int tint); + public static native void nativeVignetting(Bitmap src, Bitmap dst, float range); + public static native void nativeWarmify(Bitmap src, Bitmap dst); + public static native void nativeWhiteBlack(Bitmap src, Bitmap dst, float white, float black); +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/LomoishFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/LomoishFilter.java new file mode 100644 index 0000000..1028081 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/LomoishFilter.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Preset "Lomo-ish" applied to the image. + */ +public class LomoishFilter extends Filter { + + public LomoishFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeBlur(src.bitmap(), dst.bitmap(), 0.3f); + ImageUtils.nativeCrossProcess(dst.bitmap(), dst.bitmap()); + ImageUtils.nativeWhiteBlack(dst.bitmap(), dst.bitmap(), 0.8f, 0.15f); + ImageUtils.nativeVignetting(dst.bitmap(), dst.bitmap(), 0.73f); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/NegativeFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/NegativeFilter.java new file mode 100644 index 0000000..fda1862 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/NegativeFilter.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Negative filter applied to the image. + */ +public class NegativeFilter extends Filter { + + public NegativeFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeNegative(src.bitmap(), dst.bitmap()); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/PosterizeFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/PosterizeFilter.java new file mode 100644 index 0000000..4001a90 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/PosterizeFilter.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * "Posterize" filter applied to the image. + */ +public class PosterizeFilter extends Filter { + + public PosterizeFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeQuantize(src.bitmap(), dst.bitmap()); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/RedEyeFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/RedEyeFilter.java new file mode 100644 index 0000000..0965c61 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/RedEyeFilter.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import android.graphics.PointF; + +import com.android.photoeditor.Photo; + +import java.util.Vector; + +/** + * Red-eye removal filter applied to the image. + */ +public class RedEyeFilter extends Filter { + + private static final float RADIUS_RATIO = 0.06f; + private static final float MIN_RADIUS = 10.0f; + private static final float DEFAULT_RED_INTENSITY = 1.30f; // an empirical value + + private final Vector<PointF> redeyePositions = new Vector<PointF>(); + + public void addRedEyePosition(PointF point) { + redeyePositions.add(point); + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + float radius = Math.max(MIN_RADIUS, RADIUS_RATIO * Math.min(src.width(), src.height())); + + PointF[] a = new PointF[redeyePositions.size()]; + ImageUtils.nativeRedEye(src.bitmap(), dst.bitmap(), + redeyePositions.toArray(a), radius, DEFAULT_RED_INTENSITY); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/RotateFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/RotateFilter.java new file mode 100644 index 0000000..5152aca --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/RotateFilter.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import android.graphics.Matrix; + +import com.android.photoeditor.Photo; + +/** + * Rotate filter applied to the image. + */ +public class RotateFilter extends Filter { + + private final Matrix matrix = new Matrix(); + + public void setAngle(float degrees) { + matrix.setRotate(degrees); + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeCopy(src.bitmap(), dst.bitmap()); + dst.transform(matrix); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/SaturationFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/SaturationFilter.java new file mode 100644 index 0000000..6590670 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/SaturationFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Saturation filter applied to the image. + */ +public class SaturationFilter extends Filter { + + private float saturation; + + /** + * Sets the saturation level. + * + * @param saturation ranges from 0 to 1. + */ + public void setSaturation(float saturation) { + this.saturation = (saturation - 0.5f) * 2; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeSaturation(src.bitmap(), dst.bitmap(), saturation); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/SepiaFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/SepiaFilter.java new file mode 100644 index 0000000..696f578 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/SepiaFilter.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Sepia filter applied to the image. + */ +public class SepiaFilter extends Filter { + + public SepiaFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeSepia(src.bitmap(), dst.bitmap()); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/ShadowFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/ShadowFilter.java new file mode 100644 index 0000000..5008e6a --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/ShadowFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Shadow filter applied to the image. + */ +public class ShadowFilter extends Filter { + + private float black; + + /** + * Sets the shadow blackness level. + * + * @param shadow ranges from 0 to 1. + */ + public void setShadow(float shadow) { + black = shadow * 0.5f; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeWhiteBlack(src.bitmap(), dst.bitmap(), 1f, black); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/SharpenFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/SharpenFilter.java new file mode 100644 index 0000000..7d3aa0d --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/SharpenFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Sharpen filter applied to the image. + */ +public class SharpenFilter extends Filter { + + private float scale; + + /** + * Sets the sharpen level. + * + * @param scale ranges from 0 to 1. + */ + public void setSharpen(float scale) { + this.scale = scale; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeSharpen(src.bitmap(), dst.bitmap(), scale); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/SoftFocusFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/SoftFocusFilter.java new file mode 100644 index 0000000..d2e41a5 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/SoftFocusFilter.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Soft focus filter applied to the image. + */ +public class SoftFocusFilter extends Filter { + + private float scale; + + /** + * Sets the soft focus level. + * + * @param scale ranges from 0 to 1. + */ + public void setSoftFocus(float scale) { + this.scale = scale; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeBlur(src.bitmap(), dst.bitmap(), scale); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/StraightenFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/StraightenFilter.java new file mode 100644 index 0000000..8f265bd --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/StraightenFilter.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; + +import com.android.photoeditor.Photo; +import com.android.photoeditor.RectUtils; + +/** + * Straighten filter applied to the image. + */ +public class StraightenFilter extends Filter { + + private final RectF bounds = new RectF(); + private final Matrix matrix = new Matrix(); + private final Canvas canvas = new Canvas(); + private final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); + + private float angle; + + public void setAngle(float degrees) { + this.angle = degrees; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + bounds.set(0, 0, src.width(), src.height()); + RectUtils.getStraightenMatrix(bounds, angle, matrix); + matrix.mapRect(bounds); + matrix.postTranslate((src.width() - bounds.width()) / 2, + (src.height() - bounds.height()) / 2); + canvas.setBitmap(dst.bitmap()); + canvas.drawBitmap(src.bitmap(), matrix, paint); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/TintFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/TintFilter.java new file mode 100644 index 0000000..ef06fee --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/TintFilter.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Tint filter applied to the image. + */ +public class TintFilter extends Filter { + + private int tint; + + public void setTint(int color) { + tint = color; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeTint(src.bitmap(), dst.bitmap(), tint); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/VignetteFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/VignetteFilter.java new file mode 100644 index 0000000..3d5b566 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/VignetteFilter.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Vignette filter applied to the image. + */ +public class VignetteFilter extends Filter { + + private float range; + + /** + * Sets the vignette range scale. + * + * @param scale ranges from 0 to 1. + */ + public void setScale(float scale) { + // The 'range' is between 1.3 to 0.6. When scale is zero then range is 1.3 + // which means no vignette at all because the luminousity difference is + // less than 1/256 and will cause nothing. + range = 1.30f - (float) Math.sqrt(scale) * 0.7f; + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeVignetting(src.bitmap(), dst.bitmap(), range); + } +} diff --git a/samples/PhotoEditor/src/com/android/photoeditor/filters/WarmifyFilter.java b/samples/PhotoEditor/src/com/android/photoeditor/filters/WarmifyFilter.java new file mode 100644 index 0000000..dc745a0 --- /dev/null +++ b/samples/PhotoEditor/src/com/android/photoeditor/filters/WarmifyFilter.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.android.photoeditor.filters; + +import com.android.photoeditor.Photo; + +/** + * Warmify filter applied to the image. + */ +public class WarmifyFilter extends Filter { + + public WarmifyFilter() { + validate(); + } + + @Override + public void process(Photo src, Photo dst) { + ImageUtils.nativeWarmify(src.bitmap(), dst.bitmap()); + } +} diff --git a/samples/quake/res/drawable/app_quake.png b/samples/quake/res/drawable/app_quake.png Binary files differnew file mode 100644 index 0000000..333b723 --- /dev/null +++ b/samples/quake/res/drawable/app_quake.png diff --git a/samples/quake/res/layout/downloader.xml b/samples/quake/res/layout/downloader.xml new file mode 100644 index 0000000..968c5f2 --- /dev/null +++ b/samples/quake/res/layout/downloader.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2008 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView android:id="@+id/customText" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:padding="3dip" + android:textAppearance="?android:attr/textAppearanceLarge" /> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView android:text="@string/download_activity_progress" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:padding="3dip" + android:gravity="right" + android:textAppearance="?android:attr/textAppearanceMedium" /> + <TextView android:id="@+id/progress" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:padding="3dip" + android:textAppearance="?android:attr/textAppearanceMedium" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView android:text="@string/download_activity_time_remaining" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:padding="3dip" + android:gravity="right" + android:textAppearance="?android:attr/textAppearanceMedium" /> + <TextView android:id="@+id/time_remaining" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:padding="3dip" + android:textAppearance="?android:attr/textAppearanceMedium" /> + </LinearLayout> + + <Button android:id="@+id/cancel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginTop="5dip" + android:text="@string/download_activity_cancel" /> +</LinearLayout> diff --git a/samples/quake/res/layout/downloader_title.xml b/samples/quake/res/layout/downloader_title.xml new file mode 100644 index 0000000..eae5d33 --- /dev/null +++ b/samples/quake/res/layout/downloader_title.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2008 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/screen" + android:layout_width="match_parent" + android:layout_height="?android:attr/windowTitleSize" + android:orientation="horizontal"> + + <TextView android:id="@+id/title_text" + android:gravity="center_vertical" + android:layout_width="0dip" + android:layout_height="match_parent" + android:paddingLeft="5dip" + style="?android:attr/windowTitleStyle" + android:singleLine="true" + android:layout_weight="1" + android:ellipsize="end" /> + + <LinearLayout android:id="@+id/loading_indicator" + android:orientation="horizontal" + android:gravity="center_vertical" + android:layout_height="match_parent" + android:layout_width="wrap_content"> + + <TextView android:text="@string/download_activity_title" + android:gravity="center_vertical" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:paddingRight="5dip" + style="?android:attr/windowTitleStyle" /> + + <ProgressBar android:id="@android:id/progress" + style="?android:attr/progressBarStyleSmallTitle" + android:layout_gravity="center_vertical" + android:paddingRight="5dip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </LinearLayout> +</LinearLayout> diff --git a/samples/quake/res/menu/menu.xml b/samples/quake/res/menu/menu.xml new file mode 100644 index 0000000..4a0dfe3 --- /dev/null +++ b/samples/quake/res/menu/menu.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/switch_mode" + android:title="@string/switch_mode" /> +</menu> + diff --git a/samples/quake/res/values/strings.xml b/samples/quake/res/values/strings.xml new file mode 100644 index 0000000..3c9ee40 --- /dev/null +++ b/samples/quake/res/values/strings.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/Quake/res/strings.xml +** +** Copyright 2006, 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. +*/ +--> + +<!-- This file contains resource definitions for displayed strings, allowing + them to be changed based on the locale and options. --> + +<resources> + <!-- Simple strings. --> + <string name="quake_activity">Quake</string> + <!-- Displayed while copying Quake data to storage. CHAR LIMIT=NONE --> + <string name="quake_customDownloadText">Please wait while the Quake data files are copied.</string> + <string name="download_activity_title">Downloading</string> + <string name="download_activity_cancel">Cancel Download</string> + <string name="download_activity_progress">Progress:</string> + <string name="download_activity_time_remaining">Time Remaining:</string> + <string name="download_activity_time_remaining_unknown">unknown</string> + <string name="download_activity_time_remaining_minutes">minutes</string> + <string name="download_activity_time_remaining_seconds">seconds</string> + <string name="download_activity_time_remaining_hours">hours</string> + <string name="download_activity_time_remaining_days">days</string> + <string name="download_activity_download_stopped">Download stopped</string> + <string name="download_activity_retry">Retry</string> + <string name="download_activity_quit">Quit</string> + <string name="switch_mode">Switch Mode</string> +</resources> + diff --git a/toolchains/llvm/setup.mk b/toolchains/llvm/setup.mk index e9832f7..5a3fbc5 100644 --- a/toolchains/llvm/setup.mk +++ b/toolchains/llvm/setup.mk @@ -11,7 +11,8 @@ TARGET_C_INCLUDES := $(GDK_PLATFORMS_ROOT)/android-portable/arch-llvm/usr/include # Workaround before the required headers are in the above dir. -TARGET_C_INCLUDES += $(NDK_ROOT)/platforms/android-9/arch-arm/usr/include/ \ +TARGET_C_INCLUDES += $(NDK_ROOT)/platforms/android-9/arch-arm/usr/include \ + $(NDK_ROOT)/sources/cxx-stl/system/include \ $(NDK_ROOT)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.4.3/include TARGET_CC := $(OUT)/../../../host/linux-x86/bin/clang |