1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <android/bitmap.h> 18 #include <jni.h> 19 20 #include <cmath> 21 22 #include "utils.h" 23 #include "_jni.h" 24 25 using android::apps::photoeditor::utils::LockBitmaps; 26 using android::apps::photoeditor::utils::pixel32_t; 27 using android::apps::photoeditor::utils::UnlockBitmaps; 28 29 namespace { 30 31 const int k256Multiply255 = 65280; 32 33 void BenSaturate(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, 34 void *src_pixels, void *dst_pixels, int scale) { 35 for (uint32_t scan_line = 0; scan_line < dst_info->height; scan_line++) { 36 uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); 37 pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); 38 pixel32_t* src_end = src + src_info->width; 39 40 while (src < src_end) { 41 int kv = (src->rgba8[0] + src->rgba8[0] + src->rgba8[1] * 5 + src->rgba8[2] + 4) >> 3; 42 43 int dst_red = kv + (((src->rgba8[0] - kv) * scale) >> 8); 44 int dst_green = kv + (((src->rgba8[1] - kv) * scale) >> 8); 45 int dst_blue = kv + (((src->rgba8[2] - kv) * scale) >> 8); 46 47 *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; 48 49 dst++; 50 src++; 51 } 52 dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride; 53 src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride; 54 } 55 } 56 57 void HerfSaturate(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info, 58 void *src_pixels, void *dst_pixels, float scale) { 59 const float kMapScale = 8.0; 60 const int kMapSize = 2048; 61 int rmap[kMapSize]; 62 int gmap[kMapSize]; 63 int bmap[kMapSize]; 64 65 const float kR = 0.3; 66 const float kG = 0.7; 67 const float kB = 0.9; 68 const float amtR = (kR * scale) + 1; 69 const float amtG = (kG * scale) + 1; 70 const float amtB = (kB * scale) + 1; 71 72 for (int i = 0; i < kMapSize; i++) { 73 float inv = kMapScale * static_cast<float>(i) / kMapSize; 74 rmap[i] = static_cast<int>(pow(inv, amtR) * 256); 75 gmap[i] = static_cast<int>(pow(inv, amtG) * 256); 76 bmap[i] = static_cast<int>(pow(inv, amtB) * 256); 77 } 78 79 int kMapFactor256 = static_cast<int>(kMapSize / kMapScale) * 256; 80 for (uint32_t scan_line = 0; scan_line < dst_info->height; scan_line++) { 81 uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels); 82 pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); 83 pixel32_t* src_end = src + src_info->width; 84 85 while (src < src_end) { 86 int de = (src->rgba8[0] + src->rgba8[0] + src->rgba8[1] * 5 + src->rgba8[2]) >> 3; 87 if (!de) { 88 *dst = src->rgba8[3] << 24; 89 } else { 90 int invde = (kMapFactor256 - 1) / de; 91 int r = invde * src->rgba8[0] >> 8; 92 int g = invde * src->rgba8[1] >> 8; 93 int b = invde * src->rgba8[2] >> 8; 94 95 int dst_red = de * rmap[r] >> 8; 96 int dst_green = de * gmap[g] >> 8; 97 int dst_blue = de * bmap[b] >> 8; 98 99 int rgb_max = MAX3(dst_red, dst_green, dst_blue); 100 if (rgb_max > 255) { 101 int invmax = k256Multiply255 / rgb_max; 102 dst_red = dst_red * invmax >> 8; 103 dst_green = dst_green * invmax >> 8; 104 dst_blue = dst_blue * invmax >> 8; 105 } 106 107 *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; 108 } 109 dst++; 110 src++; 111 } 112 dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride; 113 src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride; 114 } 115 } 116 117 /* 118 * @param scale ranges from -1 to 1. 119 */ 120 extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeSaturation( 121 JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { 122 pSaturationType f = (pSaturationType)JNIFunc[JNI_Saturation].func_ptr; 123 return f(env, obj, src_bitmap, dst_bitmap, scale); 124 } 125 126 extern "C" void Saturation( 127 JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { 128 AndroidBitmapInfo src_info; 129 AndroidBitmapInfo dst_info; 130 void* src_pixels; 131 void* dst_pixels; 132 133 int ret = LockBitmaps( 134 env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); 135 if (ret < 0) { 136 LOGE("LockBitmaps in Saturation failed, error=%d", ret); 137 return; 138 } 139 140 if (scale >= 0) { 141 HerfSaturate(&src_info, &dst_info, src_pixels, dst_pixels, scale * 3); 142 } else { 143 BenSaturate(&src_info, &dst_info, src_pixels, dst_pixels, 144 static_cast<int>((1 + scale) * 256)); 145 } 146 147 UnlockBitmaps(env, src_bitmap, dst_bitmap); 148 } 149 150 } // namespace 151