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

时间:2018-03-14 00:35:52

标签: java c++ java-native-interface

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

第1部分: 我正在开发一个项目,我必须从C ++调用Java例程。

我使用以下代码来调用java方法。该参数是一个字符串数组,前两个值用于从硬盘驱动器读取文件并对其进行解码并返回数据。出于测试目的,我返回一个只包含文件中第一个图像的1D整数数组。文件中有更多的图像具有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_Environment\Test_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 ++吗?

编辑 第2部分: 我用新的Java代码和相同的C ++代码进行了测试,除了现在我正在调用&#34; getInDataS&#34;来自java方面。这是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;
}

我至少在深度变量中得到一些值,但是一旦我尝试读取值,就会抛出访问冲突。 Bothe代码行抛出错误。这是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);

1 个答案:

答案 0 :(得分:1)

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

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

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