JNI:将整数数组从Java传递到C

JNI: passing integer array from Java to C

本文关键字:Java 整数 数组 JNI      更新时间:2023-10-16

编辑:跳到第 2 部分以获得更简单的代码。

部分1:我正在做一个项目,其中我必须从C++调用Java例程。

我使用以下代码调用 java 方法。该参数是一个字符串数组,其中前 2 个值用于从硬盘驱动器读取文件解码并返回数据。出于测试目的,我返回一个仅包含文件中第一个图像的一维整数数组。文件中有更多具有 Z 深度和时间序列的图像,就像在视频中一样,暂时忽略这些图像。

mid = m_pJVMInstance->m_pEnv->GetStaticMethodID(imageJ_cls, "getIntData", "([Ljava/lang/String;)[I");
if (mid == nullptr)
cerr << "ERROR: method not found !" << endl;
else {
jobjectArray arr = m_pJVMInstance->m_pEnv->NewObjectArray(2,      // constructs java array of 2
m_pJVMInstance->m_pEnv->FindClass("java/lang/String"),    // Strings
m_pJVMInstance->m_pEnv->NewStringUTF("str"));   // each initialized with value "str"
m_pJVMInstance->m_pEnv->SetObjectArrayElement(arr, 0, m_pJVMInstance->m_pEnv->NewStringUTF("D:Dev_EnvironmentTest_Files\"));  // change an element
m_pJVMInstance->m_pEnv->SetObjectArrayElement(arr, 1, m_pJVMInstance->m_pEnv->NewStringUTF("4D_1ch.lsm"));  // change an element
jintArray depth = (jintArray)(m_pJVMInstance->m_pEnv->CallStaticIntMethod(imageJ_cls, mid, arr));   // call the method with the arr as argument.
m_pJVMInstance->m_pEnv->DeleteLocalRef(arr);     // release the object
}

方法mid正在获取正确的函数。Java 代码执行一些处理,并返回一个整数数组以C++以进行进一步处理。

Java代码:

public static int[] getIntData(String[] args) {
int[] test = new int[1];
test[0] = 1;
String dir = args[0];
String name = args[1];
String id = dir + name;
ImageProcessorReader ip_reader = new ImageProcessorReader(
new ChannelSeparator(LociPrefs.makeImageReader()));
try {
IJ.showStatus("Examining file " + name);
ip_reader.setId(id);
int num = ip_reader.getImageCount();
int width = ip_reader.getSizeX();
int height = ip_reader.getSizeY();
ImageStack stack = new ImageStack(width, height);
byte[][][] lookupTable = new byte[ip_reader.getSizeC()][][];
//TODO: Don't know how to handle multiple channels i.e RGb images currently.
// Adding all the slices into a 2D array and returning those values.
int[] test_array = new int[width*height];
int[][][] return_array = new int[height][width][num];
for (int i=0; i<num; i++) {
IJ.showStatus("Reading image plane #" + (i + 1) + "/" + num);
ImageProcessor ip = ip_reader.openProcessors(i)[0];
// Copying the value to the return array.
int[][] temp_array = ip.getIntArray();
for (int h=0; h < height; h++) {
for (int w = 0; w < width; w++) {
return_array[h][w][i] = temp_array[h][w];
if (i==0){
test_array[h*width + w] = temp_array[h][w];
}
}
}
//java.awt.image.BufferedImage awt_Ip =  ip.getBufferedImage();
//ImageIO.write(awt_Ip, "jpg", new File("D:\Dev_Environment\Test_Files\Test_Folder\out" + Integer.toString(i) + ".jpg"));
stack.addSlice("" + (i + 1), ip);
int channel = ip_reader.getZCTCoords(i)[1];
lookupTable[channel] = ip_reader.get8BitLookupTable();
}
IJ.showStatus("Constructing image");
ImagePlus imp = new ImagePlus(name, stack);
// ImagePlus show is leading to java window not responding, maybe it is because this program is not a imageJ plugin but a standalone program.
//imp.show();
//ImagePlus colorizedImage = applyLookupTables(r, imp, lookupTable);
//r.close();
//colorizedImage.show();
IJ.showStatus("");
test[0] = 2;
return test;
}
catch (FormatException exc) {
IJ.error("Sorry, an error occurred: " + exc.getMessage());
test[0] = 3;
}
catch (IOException exc) {
IJ.error("Sorry, an error occurred: " + exc.getMessage());
test[0] = 4;
}
return test;
}

仅出于测试,我添加了一个大小为 1 的测试数组来检查 C++ 中的输出。我在深度变量中得到 0 作为返回值。

我的问题是我们如何将整数数组从 Java 返回到 c++?jintArray是正确的方式吗?因此,我可以将 3D 数组从 Java 返回到C++吗?

编辑篇二:我用新的Java代码和相同的C++代码做了一个测试,只是现在我从java端调用"getInDataS"。这是java代码:

public static int[] getIntDataS(String[] args) {
int[] test = new int[10];
test[0] = 10;
test[1] = 10;
test[2] = 10;
test[3] = 10;
test[4] = 10;
test[5] = 10;
test[6] = 10;
test[7] = 10;
test[8] = 10;
test[9] = 10;
return test;
}

我至少在深度变量中获得了一些值,但是一旦我尝试读取值,就会抛出访问冲突。代码行抛出错误。这是C++代码:

jintArray depth = (jintArray)(m_pJVMInstance->m_pEnv->CallStaticIntMethod(imageJ_cls, mid, arr));
jsize len = m_pJVMInstance->m_pEnv->GetArrayLength(depth);
jint* body = m_pJVMInstance->m_pEnv->GetIntArrayElements(depth, 0);

返回 int 数组的工作方式与您描述的完全一样,但调用此类 Java 方法的 JNI 函数不是 CallStaticIntMethod(),而是 CallStaticObjectMethod()。这是您收到错误的最可能原因。

要接受 C 语言中的二维数组(或更多),请将其声明为 jobjectArray,并将每个元素的对象值获取为 jintArray。

请注意,您的 C 代码会泄漏一些本地引用,如果在循环中调用它,这可能是一个问题。用 PushLocalFrame() 和 PopLocalFrame() 包装这段代码可能更容易。