Chendd's Blog

世界上没有什么事情是一行代码不能解决的。如果有,那就两行。

深入了解android平台的jni(三)

一、涉及到的jni编程知识

       Java基本类型的数组,在JNI中都是jArray的类型格式。具体类型如下:
typedef jarray jbooleanArray;
typedef jarray jbyteArray;
typedef jarray jcharArray;
typedef jarray jshortArray;
typedef jarray jintArray;
typedef jarray jlongArray;
typedef jarray jfloatArray;
typedef jarray jdoubleArray;
typedef jarray jobjectArray;

       jArray类型JNI定义的类型,通过它JNIEnv可以操作Java数组,但它并不是C/C++的数组,所以我们要把jArray类型转换为C/C++中的数组。 JNIEnv定义了一系列的方法来把一个jArray类型转换为C/C++数组,和把C/C++数组转换为jArray

1、Java基本类型的数组转换成相应的C数组类型

jbooleanGetBooleanArrayElements)(JNIEnv, jbooleanArray, jboolean);
jbyteGetByteArrayElements)(JNIEnv, jbyteArray, jboolean);
jcharGetCharArrayElements)(JNIEnv, jcharArray, jboolean);
jshortGetShortArrayElements)(JNIEnv, jshortArray, jboolean);
jintGetIntArrayElements)(JNIEnv, jintArray, jboolean);
jlongGetLongArrayElements)(JNIEnv, jlongArray, jboolean);
jfloatGetFloatArrayElements)(JNIEnv, jfloatArray, jboolean);
jdoubleGetDoubleArrayElements)(JNIEnv, jdoubleArray, jboolean);

参数: env:JNI 接口指针。
array:Java 字符串对象。
isCopy:指向布尔值的指针。
返回值:
返回指向数组元素的指针,如果操作失败,则为 NULL。

2、获取数组的长度:

jsize (GetArrayLength)(JNIEnv, jarray);

3、释放C/C++的数组内存

void (ReleaseBooleanArrayElements)(JNIEnv, jbooleanArray,jboolean, jint);
void (
ReleaseByteArrayElements)(JNIEnv, jbyteArray,jbyte, jint);
void (ReleaseCharArrayElements)(JNIEnv, jcharArray,jchar, jint);
void (
ReleaseShortArrayElements)(JNIEnv, jshortArray,jshort, jint);
void (ReleaseIntArrayElements)(JNIEnv, jintArray,jint, jint);
void (
ReleaseLongArrayElements)(JNIEnv, jlongArray,jlong, jint);
void (ReleaseFloatArrayElements)(JNIEnv, jfloatArray,jfloat, jint);
void (
ReleaseDoubleArrayElements)(JNIEnv, jdoubleArray,jdouble, jint);
参数:
env:JNI 接口指针。
array:Java 数组对象。
elems:指向数组元素的指针。
mode:释放模式。

4、构造一个指定长度的Java基本类型的数组

jbooleanArray (NewBooleanArray)(JNIEnv, jsize);
jbyteArray (NewByteArray)(JNIEnv, jsize);
jcharArray (NewCharArray)(JNIEnv, jsize);
jshortArray (NewShortArray)(JNIEnv, jsize);
jintArray (NewIntArray)(JNIEnv, jsize);
jlongArray (NewLongArray)(JNIEnv, jsize);
jfloatArray (NewFloatArray)(JNIEnv, jsize);
jdoubleArray (NewDoubleArray)(JNIEnv, jsize);

5、给java基本类型的数组赋值

void (SetBooleanArrayRegion)(JNIEnv, jbooleanArray,jsize, jsize, const jboolean);
void (
SetByteArrayRegion)(JNIEnv, jbyteArray,jsize, jsize, const jbyte);
void (SetCharArrayRegion)(JNIEnv, jcharArray,jsize, jsize, const jchar);
void (
SetShortArrayRegion)(JNIEnv, jshortArray,jsize, jsize, const jshort);
void (SetIntArrayRegion)(JNIEnv, jintArray,jsize, jsize, const jint);
void (
SetLongArrayRegion)(JNIEnv, jlongArray,jsize, jsize, const jlong);
void (SetFloatArrayRegion)(JNIEnv, jfloatArray,jsize, jsize, const jfloat);
void (
SetDoubleArrayRegion)(JNIEnv, jdoubleArray, jsize, jsize, const jdouble);
把java基本类型的数组中的指定范围的元素用C/C++的数组中的元素来赋值 参数:
env:JNI 接口指针。
array: Java 数组。
start:起始下标。
len:要复制的元素数。
buf:源缓冲区。
抛出:
ArrayIndexOutOfBoundsException:如果区域中的某个下标无效。 注意: 如果是c程序,要用 (env)-> 如果是C++要用 env-> 在linux下如果.c文件中用 “env->” 编译会找不到此结构,必须用“(env)->”,或者改成.cpp文件,以 c++的方式来编译。 具体请看一下jni.h的代码。另外还有些省略的内容,可以参考JNI的文档:Java Native Interface 6.0 Specification,在JDK的文档里就可以找到。如果要进行更深入的JNI编程,需要仔细阅读这个文档

二、图像灰度化

       彩色转灰度的著名心理学公式:Gray = R0.299 + G0.587 + B*0.114 实际应用中为了避免浮点运算,然后就有了移位运算代替了。 2至20位精度的系数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Gray = (R*1 + G*2 + B*1) >> 2
Gray = (R*2 + G*5 + B*1) >> 3
Gray = (R*4 + G*10 + B*2) >> 4
Gray = (R*9 + G*19 + B*4) >> 5
Gray = (R*19 + G*37 + B*8) >> 6
Gray = (R*38 + G*75 + B*15) >> 7
Gray = (R*76 + G*150 + B*30) >> 8
Gray = (R*153 + G*300 + B*59) >> 9
Gray = (R*306 + G*601 + B*117) >> 10
Gray = (R*612 + G*1202 + B*234) >> 11
Gray = (R*1224 + G*2405 + B*467) >> 12
Gray = (R*2449 + G*4809 + B*934) >> 13
Gray = (R*4898 + G*9618 + B*1868) >> 14
Gray = (R*9797 + G*19235 + B*3736) >> 15
Gray = (R*19595 + G*38469 + B*7472) >> 16
Gray = (R*39190 + G*76939 + B*14943) >> 17
Gray = (R*78381 + G*153878 + B*29885) >> 18
Gray = (R*156762 + G*307757 + B*59769) >> 19
Gray = (R*313524 + G*615514 + B*119538) >> 20

三、灰度化代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
JNIEXPORT jintArray JNICALL Java_org_join_image_util_JoinImage_imgToGray(
        JNIEnv* env, jobject obj, jintArray buf, int w, int h) {
    LOGE("==imgToGray==");

    jint * cbuf;
    cbuf = (*env)->GetIntArrayElements(env, buf, 0); // 获取int数组元素 

    int alpha = 0xFF; // 不透明值 
    int i, j, color, red, green, blue;
    for (i = 0; i < h; i++) {
        for (j = 0; j < w; j++) {
            color = cbuf[w * i + j]; // 获得color值 
            red = (color >> 16) & 0xFF; // 获得red值 
            green = (color >> 8) & 0xFF; // 获得green值 
            blue = color & 0xFF; // 获得blue值 
            color = (red * 38 + green * 75 + blue * 15) >> 7; // 灰度算法(16位运算下7位精度) 
            color = (alpha << 24) | (color << 16) | (color << 8) | color; // 由ARGB组成新的color值 
            cbuf[w * i + j] = color; // 设置新color值 
        }
    }

    int size = w * h;
    jintArray result = (*env)->NewIntArray(env, size); // 新建一个jintArray 
    (*env)->SetIntArrayRegion(env, result, 0, size, cbuf); // 将cbuf转存入result 
    (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); // 释放int数组元素 
    return result;
}

Comments