Edit: Skip to part 2 for a simpler code.
Part 1: I am working on a project wherein I have to call Java routines from C++.
I use the following code to call the java method. The parameter is a string array from which the first 2 values are used to read a file from the hard drive decode it and return the data. For testing purpose, I am returning a 1D integer array containing only the first image in the file. There are more images in the file with Z depth and time sequence like in a video, ignoring those for now.
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
}
The method mid is getting the correct function. The Java code does some processing and returns a integer array to C++ for further processing.
The Java code:
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;
}
For testing only I added a test array of size 1 to check the output in C++. I am getting 0 as a return value in the depth variable.
My question is how do we return an integer array from Java to c++? Is jintArray the right way? Consequently, can I return a 3D array from Java to C++?
Edit Part 2: I did a test with new Java code and same C++ code, except now I am calling "getInDataS" from the java side. Here is the java code:
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;
}
I am atleast getting some value in the depth variable but as soon as I try to read the values access violation is thrown. Bothe the lines of code throw the error. Here is the C++ Code:
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);