今天继续学习C与Java通过JNIEnv交互。
定位方法,如下:
现在就用它们来实现一个图像处理的效果,其实也很简单,Java层把图像矩阵传给C层,C对图像进行处理,为了体现读取变量和调用方法,图像矩阵就不以参数形式提供给C层,而在C层分别通过读取成员变量和调用成员方法来获取图像矩阵。
定义工具类:
昨天学习了C与Java交互方法,但感觉太轻松了,就像调用findViewById一样简单,可能是我遗漏了什么东西,于是就想在今天继续研究这一块儿的内容,顺便做一下总结。
C调用Java的方法和访问Java中的变量都是通过JNIEnv进行的,它提供了一堆方法用来定位、调用方法和定位、读取变量:
GetFieldID(jclass clazz, const char* name, const char* sig); //获取非静态成员变量的Id GetStaticFieldID(jclass clazz, const char* name, const char* sig); //获取静态成员变量的Id GetMethodID(jclass clazz, const char* name, const char* sig); //获取非静态方法的Id GetStaticMethodID(jclass clazz, const char* name, const char* sig); //获取静态方法的Id它们都是通过 变量名/方法名和签名(签名规则见前一章)来获取ID的。
读取和调用方法,如下:
GetXxxField(jobject obj, jfieldID fieldID); //读取非静态成员变量的值 GetStaticXxxField(jclass clazz, jfieldID fieldID); //读取静态成员变量的值 CallXxxMethod(jobject obj, jmethodID methodID, ...) //调用非静态方法 CallStaticXxxMethod(jclass clazz, jmethodID methodID, ...) //调用静态方法它们都是 类/对象和刚才确定的ID实现读取和调用的。
现在就用它们来实现一个图像处理的效果,其实也很简单,Java层把图像矩阵传给C层,C对图像进行处理,为了体现读取变量和调用方法,图像矩阵就不以参数形式提供给C层,而在C层分别通过读取成员变量和调用成员方法来获取图像矩阵。
定义工具类:
public class ColorConvertHelper { static { System.loadLibrary("native-lib"); } private int[] mColorMatrix; //设置图像矩阵 public void setMatrix(int[] colorMatrix){ mColorMatrix = colorMatrix; } //获取图像矩阵 public int[] getMatrix(){ return mColorMatrix; } public ColorConvertHelper(int[] matrix){ mColorMatrix = matrix; } //处理图像,values为处理的值,w、h为图像宽和高 public native int[] changeColorMatrix(int values,int w,int h); }
public native int[] changeColorMatrix(int values,int w,int h);中的values是通过Seekbar传给自定义的ImageView的,这个方法在ImageView中调用,并且获得返回结果后会调用刷新方法,在OnDraw里将返回结果设置给新的bitmap,再进行绘制,有兴趣的可以自己动手试试,这里就不贴代码了,写得真的乱。
在C层实现该方法
#include <jni.h> extern "C" JNIEXPORT jintArray JNICALL Java_com_tustcs_ndktest_ColorConvertHelper_changeColorMatrix(JNIEnv *env, jobject instance, jint values,int w ,int h) { jclass mClass = env->GetObjectClass(instance); //获取当前类型 //获取矩阵的方法一:通过直接访问对象成员变量获取 jfieldID mFieldId = env->GetFieldID(mClass,"mColorMatrix","[I"); //获取成员变量ID jintArray mArray = (jintArray)env->GetObjectField(instance,mFieldId); //强转得到数组类型 // 获取矩阵的方法二:通过直接访问对象的get方法获取 // jmethodID mMethodId = env->GetMethodID(mClass,"getMatrix","()[I"); //获取方法ID // jintArray mArray = (jintArray)env->CallObjectMethod(instance,mMethodId); //强转得到数组类型 int * array = env->GetIntArrayElements(mArray,NULL); jsize size = env->GetArrayLength(mArray); int alpha = 0xFF << 24; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { int color = array[w * i + j]; int red = ((color & 0x00FF0000) >> 16); int green = ((color & 0x0000FF00) >> 8); int blue = color & 0x000000FF; red = red - values; green = green - values; blue = blue - values; color = alpha | (red << 16) | (green << 8) | blue; array[w * i + j] = color; } } jintArray result = env->NewIntArray(size); env->SetIntArrayRegion(result, 0, size, array); env->ReleaseIntArrayElements(mArray, array, 0); return result; }
这里分别使用了调用方法和读取成员变量这两种方式来获取图像矩阵。
代码写到这里花了不少时间,笔者看到env->GetIntArrayElements(mArray,NULL);方法就想当然的认为有提供类似env->GetIntArrayField(instance,mFieldId); 的方法,事实上并没有,C层直接获取Java层的数组类需要通过env->GetObjectField(instance,mFieldId);然后进行强制类型转换才能得到。这里是对图像矩阵做了乱七八糟的处理,我也不知道这叫什么效果。