10f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh/*
20f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * Copyright (C) 2010 The Android Open Source Project
30f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh *
40f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * Licensed under the Apache License, Version 2.0 (the "License");
50f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * you may not use this file except in compliance with the License.
60f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * You may obtain a copy of the License at
70f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh *
80f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh *      http://www.apache.org/licenses/LICENSE-2.0
90f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh *
100f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * Unless required by applicable law or agreed to in writing, software
110f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * distributed under the License is distributed on an "AS IS" BASIS,
120f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * See the License for the specific language governing permissions and
140f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * limitations under the License.
150f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh */
160f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
170f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh#include <android/bitmap.h>
180f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh#include <jni.h>
190f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
200f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh#include <cmath>
210f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
220f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh#include "utils.h"
230f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh#include "_jni.h"
240f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
250f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehusing android::apps::photoeditor::utils::LockBitmaps;
260f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehusing android::apps::photoeditor::utils::pixel32_t;
270f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehusing android::apps::photoeditor::utils::UnlockBitmaps;
280f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
290f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehnamespace {
300f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
310f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehconst int k256Multiply255 = 65280;
320f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
330f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehvoid BenSaturate(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info,
340f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    void *src_pixels, void *dst_pixels, int scale) {
350f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  for (uint32_t scan_line = 0; scan_line < dst_info->height; scan_line++) {
360f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels);
370f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels);
380f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    pixel32_t* src_end = src + src_info->width;
390f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
400f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    while (src < src_end) {
410f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      int kv = (src->rgba8[0] + src->rgba8[0] + src->rgba8[1] * 5 + src->rgba8[2] + 4) >> 3;
420f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
430f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      int dst_red = kv + (((src->rgba8[0] - kv) * scale) >> 8);
440f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      int dst_green = kv + (((src->rgba8[1] - kv) * scale) >> 8);
450f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      int dst_blue = kv + (((src->rgba8[2] - kv) * scale) >> 8);
460f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
470f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red;
480f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
490f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      dst++;
500f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      src++;
510f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    }
520f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride;
530f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride;
540f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  }
550f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh}
560f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
570f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehvoid HerfSaturate(AndroidBitmapInfo *src_info, AndroidBitmapInfo *dst_info,
580f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      void *src_pixels, void *dst_pixels, float scale) {
590f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const float kMapScale = 8.0;
600f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const int kMapSize = 2048;
610f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  int rmap[kMapSize];
620f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  int gmap[kMapSize];
630f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  int bmap[kMapSize];
640f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
650f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const float kR = 0.3;
660f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const float kG = 0.7;
670f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const float kB = 0.9;
680f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const float amtR = (kR * scale) + 1;
690f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const float amtG = (kG * scale) + 1;
700f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  const float amtB = (kB * scale) + 1;
710f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
720f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  for (int i = 0; i < kMapSize; i++) {
730f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      float inv = kMapScale * static_cast<float>(i) / kMapSize;
740f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      rmap[i] = static_cast<int>(pow(inv, amtR) * 256);
750f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      gmap[i] = static_cast<int>(pow(inv, amtG) * 256);
760f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      bmap[i] = static_cast<int>(pow(inv, amtB) * 256);
770f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  }
780f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
790f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  int kMapFactor256 = static_cast<int>(kMapSize / kMapScale) * 256;
800f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  for (uint32_t scan_line = 0; scan_line < dst_info->height; scan_line++) {
810f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    uint32_t* dst = reinterpret_cast<uint32_t*>(dst_pixels);
820f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels);
830f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    pixel32_t* src_end = src + src_info->width;
840f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
850f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    while (src < src_end) {
860f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      int de = (src->rgba8[0] + src->rgba8[0] + src->rgba8[1] * 5 + src->rgba8[2]) >> 3;
870f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      if (!de) {
880f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh          *dst = src->rgba8[3] << 24;
890f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      } else {
900f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int invde = (kMapFactor256 - 1) / de;
910f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int r = invde * src->rgba8[0] >> 8;
920f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int g = invde * src->rgba8[1] >> 8;
930f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int b = invde * src->rgba8[2] >> 8;
940f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
950f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int dst_red = de * rmap[r] >> 8;
960f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int dst_green = de * gmap[g] >> 8;
970f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int dst_blue = de * bmap[b] >> 8;
980f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
990f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        int rgb_max = MAX3(dst_red, dst_green, dst_blue);
1000f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        if (rgb_max > 255) {
1010f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh          int invmax = k256Multiply255 / rgb_max;
1020f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh          dst_red = dst_red * invmax >> 8;
1030f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh          dst_green = dst_green * invmax >> 8;
1040f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh          dst_blue = dst_blue * invmax >> 8;
1050f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        }
1060f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
1070f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        *dst = (src->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red;
1080f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      }
1090f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      dst++;
1100f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      src++;
1110f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    }
1120f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    dst_pixels = reinterpret_cast<char*>(dst_pixels) + dst_info->stride;
1130f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    src_pixels = reinterpret_cast<char*>(src_pixels) + src_info->stride;
1140f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  }
1150f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh}
1160f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
1170f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh/*
1180f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh * @param scale ranges from -1 to 1.
1190f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh */
1200f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehextern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeSaturation(
1210f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) {
1220f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh   pSaturationType f = (pSaturationType)JNIFunc[JNI_Saturation].func_ptr;
1230f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh   return f(env, obj, src_bitmap, dst_bitmap, scale);
1240f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh}
1250f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
1260f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsiehextern "C" void Saturation(
1270f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) {
1280f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  AndroidBitmapInfo src_info;
1290f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  AndroidBitmapInfo dst_info;
1300f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  void* src_pixels;
1310f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  void* dst_pixels;
1320f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
1330f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  int ret = LockBitmaps(
1340f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh      env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels);
1350f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  if (ret < 0) {
1360f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    LOGE("LockBitmaps in Saturation failed, error=%d", ret);
1370f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    return;
1380f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  }
1390f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
1400f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  if (scale >= 0) {
1410f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    HerfSaturate(&src_info, &dst_info, src_pixels, dst_pixels, scale * 3);
1420f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  } else {
1430f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh    BenSaturate(&src_info, &dst_info, src_pixels, dst_pixels,
1440f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh        static_cast<int>((1 + scale) * 256));
1450f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  }
1460f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
1470f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh  UnlockBitmaps(env, src_bitmap, dst_bitmap);
1480f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh}
1490f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh
1500f8a40e4cfdc5f6cd47c22e81f69ed0446067c54Andrew Hsieh}  // namespace
151