//
// Created by dizi on 2024/7/12.
//

#include "include/image_tools.h"


/**
 * 生成一个空的ARGB8888的Bitmap
 * @param env
 * @param width
 * @param height
 * @return
 */
jobject generate_empty_argb8888_bitmap(JNIEnv *env, int width, int height){
    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
    jmethodID constructorID = env->GetStaticMethodID(bitmapClass, "createBitmap","(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
    jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
    jfieldID argb8888FieldID = env->GetStaticFieldID(bitmapConfigClass, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
    jobject argb8888Value = env->GetStaticObjectField(bitmapConfigClass, argb8888FieldID);
    // 创建Bitmap对象
    return env->CallStaticObjectMethod(bitmapClass, constructorID, width, height, argb8888Value);
}

/**
 * 将Bitmap转Mat
 * @param env
 * @param bitmap
 * @return
 */
cv::Mat convert_bitmap_to_mat(JNIEnv *env, jobject bitmap){
    cv::Mat mat;
    // bitmap转mat
    // 获取Bitmap的信息
    AndroidBitmapInfo info;
    AndroidBitmap_getInfo(env, bitmap, &info);
    // 根据Bitmap的图片格式决定type
    int type;
    if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){
//        LOGD("CV_8UC4");
        type = CV_8UC4;
    }
    else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565){
//        LOGD("CV_8UC2");
        type = CV_8UC2;
    }
    else{
        LOGD("channel error");
        return mat;
    }
    // 获取Bitmap的像素
    void * pixels;
    AndroidBitmap_lockPixels(env, bitmap, &pixels);
    if (pixels == nullptr){
        return mat;
    }
    // Bitmap转Mat
    mat = cv::Mat(info.height, info.width, type, pixels);
    // 解锁
    AndroidBitmap_unlockPixels(env, bitmap);
    return mat;
}

/**
 * 将Mat转化为Bitmap
 * @param env
 * @param mat
 * @return
 */
jobject convert_mat_to_bitmap(JNIEnv *env, cv::Mat mat){
    AndroidBitmapInfo info;
    void *pixels = 0;
    // 生成Bitmap
    jobject bitmap = generate_empty_argb8888_bitmap(env, mat.cols, mat.rows);

    try {
        CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
        CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
                  info.format == ANDROID_BITMAP_FORMAT_RGB_565);
        CV_Assert(mat.dims == 2 && info.height == (uint32_t) mat.rows && info.width == (uint32_t) mat.cols);
        CV_Assert(mat.type() == CV_8UC1 || mat.type() == CV_8UC3 || mat.type() == CV_8UC4);
        CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
        CV_Assert(pixels);
        if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
            cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if (mat.type() == CV_8UC1) {
                cvtColor(mat, tmp, cv::COLOR_GRAY2RGBA);
            } else if (mat.type() == CV_8UC3) {
                cvtColor(mat, tmp, cv::COLOR_RGB2RGBA);
            } else if (mat.type() == CV_8UC4) {
                mat.copyTo(tmp);
            }
        } else {
            cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
            if (mat.type() == CV_8UC1) {
                cvtColor(mat, tmp, cv::COLOR_GRAY2BGR565);
            } else if (mat.type() == CV_8UC3) {
                cvtColor(mat, tmp, cv::COLOR_RGB2BGR565);
            } else if (mat.type() == CV_8UC4) {
                cvtColor(mat, tmp, cv::COLOR_RGBA2BGR565);
            }
        }
        AndroidBitmap_unlockPixels(env, bitmap);
    } catch (const cv::Exception &e) {
        AndroidBitmap_unlockPixels(env, bitmap);
        LOGE("nMatToBitmap catched cv::Exception: %s", e.what());
        jclass je = env->FindClass("org/opencv/core/CvException");
        if (!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
    } catch (...) {
        AndroidBitmap_unlockPixels(env, bitmap);
        LOGE("nMatToBitmap catched unknown exception (...)");
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
    }
    return bitmap;
}

/**
 * 在MAT上绘制框
 * @param mat 三通道
 * @param left_top_x
 * @param left_top_y
 * @param right_bottom_x
 * @param right_bottom_y
 * @return
 */
cv::Mat draw_rect_on_mat(cv::Mat mat, int left_top_x, int left_top_y, int right_bottom_x, int right_bottom_y){
    // 声明左上角和右下角坐标
    cv::Point point_left_top(left_top_x, left_top_y);
    cv::Point point_right_bottom(right_bottom_x, right_bottom_y);
    // 定义颜色和线宽度 bgr
    cv::Scalar color(0, 0, 255);
    int thickness = 2;
    // 画框
    cv::rectangle(mat, point_left_top, point_right_bottom, color, thickness);

    return mat;
}

cv::Mat draw_rect_text_on_mat(cv::Mat mat, int left_top_x, int left_top_y, int right_bottom_x, int right_bottom_y, char* text){
    // 声明左上角和右下角坐标
    cv::Point point_left_top(left_top_x, left_top_y);
    cv::Point point_right_bottom(right_bottom_x, right_bottom_y);
    // 定义颜色和线宽度 bgr
    cv::Scalar red  (0, 0, 255);
    cv::Scalar green(0, 255, 0);
    int thickness = 2;
    if (strcmp(text, "未知商品") == 0){
        // 画框
        cv::rectangle(mat, point_left_top, point_right_bottom, red, thickness);
        // 绘制文字
        cv::putText(mat, text, point_left_top, cv::HersheyFonts::FONT_HERSHEY_SIMPLEX, 1, red, thickness);
    }
    else{
        // 画框
        cv::rectangle(mat, point_left_top, point_right_bottom, green, thickness);
        // 绘制文字
        cv::putText(mat, text, point_left_top, cv::HersheyFonts::FONT_HERSHEY_SIMPLEX, 1, green, thickness);
    }


    return mat;
}

/**
 * 在图片上绘制框和文字
 */
extern "C"
JNIEXPORT jobject JNICALL
Java_com_wmdigit_core_opencv_OpencvRepository_drawRectAndTextOnBitmap(JNIEnv *env, jobject thiz,
                                                                      jobject bitmap,
                                                                      jobjectArray points,
                                                                      jobjectArray product_names) {
    // bitmap转mat
    cv::Mat mat = convert_bitmap_to_mat(env, bitmap);
    cv::Mat mat_bgr;
    cv::cvtColor(mat, mat_bgr, CV_RGBA2BGR);
    // jobjectarray转int**
    int ** points_array = convert_jobjectArray_to_intArrayArray(env, points);
    // jobjectArray转char**
    JStringInfo * jStringInfo = convert_jobjectArray_to_charArrayArray(env, product_names);
    // 框数量
    int count = env->GetArrayLength(points);
    LOGD("COUNT:%d", count);
    // 遍历数组,绘制框和文字
    for (int i = 0; i < count; i++) {
        LOGD("%d, %d, %d, %d, %s", points_array[i][0], points_array[i][1], points_array[i][2], points_array[i][3], jStringInfo[i].str);
        mat_bgr = draw_rect_text_on_mat(mat_bgr, points_array[i][0], points_array[i][1], points_array[i][2], points_array[i][3], jStringInfo[i].str);
    }
    // mat转Bitmap
    cv::Mat mat_rgb;
    cv::cvtColor(mat_bgr, mat_rgb, CV_BGR2RGB);
    jobject result = convert_mat_to_bitmap(env, mat_rgb);
    // 释放资源
    freeStringArray(jStringInfo, count);
    mat.release();
    mat_bgr.release();
    mat_rgb.release();
    freeIntArrayArray(points_array, count);
    return result;
}