将数据从非托管内存指针复制到Java中的托管无符号字节数组

huangapple go评论73阅读模式
英文:

Copy data from an unmanaged memory pointer to a managed unsigned byte array in Java

问题

Java Implementation:

public interface RSPreviewDataCallback extends Callback {
    void RSPreviewDataCallback(int deviceHandle, int errorCode, Pointer imageData, int imageWidth, int imageHeight);
}

public interface RS_SDK extends StdCallLibrary {
    RS_SDK INSTANCE = (RS_SDK) Native.load("RS_SDK_64", RS_SDK.class);

    int RS_RegisterPreviewCallback(int deviceHandle, RSPreviewDataCallback captureCallback);
}

@Override
public void RSPreviewDataCallback(int deviceHandle, int errorCode, Pointer imageData, int imageWidth, int imageHeight) {
    byte[] dataByteArray = new byte[imageWidth * imageHeight];
    imageData.read(0, dataByteArray, 0, dataByteArray.length);
    try {
        String data = new String(dataByteArray, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
}

Error:

java.lang.ArrayStoreException: arraycopy: source type com.sun.jna.Pointer is not an array

Note:

  1. The Java code provided is your translated Java implementation of the given C# code snippet.
  2. The error you're encountering is due to the incorrect use of System.arraycopy with a Pointer object. Instead, use the read method on the Pointer object to copy data from native memory to a Java byte array.
  3. The RSPreviewDataCallback interface signature seems correct based on the C# delegate definition.
  4. The updated Java code should address the memory copy issue and the error you were facing.
英文:

I have a c# code I am trying to implement in Java using JNA currently stuck in returning a preview image during my device scan process

C#

[DllImport("RS_SDK.dll",
          CharSet = CharSet.Ansi,
        EntryPoint = "RS_RegisterPreviewCallback")]
        public static extern int RS_RegisterPreviewCallback(int deviceHandle, RSPreviewDataCallback captureCallback); 


public delegate void RSRawPreviewCallback(int errorCode, byte[] imageData, int imageWidth, int imageHeight);


RSPreviewDataCallback previewCallback = new RSPreviewDataCallback(previewDataCallback);

private void previewDataCallback(int deviceHandle, int errorCode, IntPtr imageData, int imageWidth, int imageHeight)
        {
            log("previewDataCallback called....");
            if (imageData != null)
            {
                int prevImageWidth = imageWidth;
                int prevImageHeight = imageHeight;
                byte[] prevImageData = new byte[imageWidth * imageHeight];
                Marshal.Copy(imageData, prevImageData, 0, imageWidth * imageHeight);
                
                RSRawPreviewCallback callback = new RSRawPreviewCallback(previewCallbackInt);
                Invoke(callback, errorCode, prevImageData, prevImageWidth, prevImageHeight);
            }
            log("previewDataCallback done....");
        }

m_result = RS_RegisterPreviewCallback(deviceHandle,previewCallback);

My Java implementation so far

public interface RSPreviewDataCallback extends Callback {
        void RSPreviewDataCallback(int deviceHandle, int errorCode, Pointer imageData, int imageWidth, int imageHeight);
    }

public interface RS_SDK extends StdCallLibrary {
        RS_SDK INSTANCE = (RS_SDK)
                Native.load("RS_SDK_64", RS_SDK.class);

int RS_RegisterPreviewCallback(int deviceHandle, RSPreviewDataCallback captureCallback);
}

    @Override
    public void RSPreviewDataCallback(int deviceHandle, int errorCode, Pointer imageData, int imageWidth, int imageHeight) {

        byte[] dataByteArray = new byte[imageWidth * imageHeight];
        System.arraycopy( imageData, 0, dataByteArray, 0, imageWidth * imageHeight);
        try {
            String data = new String(dataByteArray, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

    }

and I run into this error:

java.lang.ArrayStoreException: arraycopy: source type com.sun.jna.Pointer is not an array
	at java.base/java.lang.System.arraycopy(Native Method)

I believe the imageData is a memory reference of the byte array and Marshal.Copy(imageData, prevImageData, 0, imageWidth * imageHeight); copies the location in memory to the bitmap array.

  1. I am not sure if my interface RSPreviewDataCallback signature is correct
  2. I don't know if there is a JNA equivalent to copy the memory location to a byte array

答案1

得分: 1

关于问题2,从Pointer获取字节数组的JNA调用是Pointer.getByteArray()。所以你可以使用imageData.getByteArray(0, imagewidth * imageheight)从指针中获取字节。

需要注意的是,Java没有无符号的byte变量,所以虽然二进制是正确的,但你需要执行一个转换到更宽类型以获取正值。位掩码b & 0xff会将其扩展为int,并还原为“无符号”值。

关于问题1,如果你使用问题2的答案,映射将起作用。在大多数JNA函数映射中,你可以通过将byte[]数组作为参数来简化此过程。然而,JNA需要为回调具体映射的类型,所以原始数组不包括在内,因此更推荐使用Pointer方法。

英文:

Regarding question 2, the JNA call to get a byte array from a Pointer is Pointer.getByteArray(). So you could grab the bytes from the pointer using imageData.getByteArray(0, imagewidth * imageheight).

Note that Java does not have unsigned byte variables, so while the binary will be correct, you'll have to perform a conversion to a wider type to get the positive value. The bitmask b & 0xff will widen to an int for you and restore the "unsigned" value.

Regarding question 1, the mapping will work if you use the answer to question2. In most JNA function mappings of arrays, you can simplify this by putting a byte[] array as the argument. However, JNA requires specifically mapped types for callbacks, so primitive arrays aren't included, so the Pointer method is preferred.

huangapple
  • 本文由 发表于 2020年9月29日 01:04:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/64106564.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定