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

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

我有一个 C# 代码,我正尝试在 Java 中使用 JNA 在我的设备扫描过程中返回预览图像

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);

到目前为止我的 Java 实现

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();
        }

    }

我 运行 遇到这个错误:

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

我相信 imageData 是字节数组的内存引用,Marshal.Copy(imageData, prevImageData, 0, imageWidth * imageHeight); 将内存中的位置复制到位图数组。

  1. 我不确定我的界面 RSPreviewDataCallback 签名是否正确
  2. 不知道有没有JNA相当于把内存位置复制到字节数组

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

从指针中获取字节

请注意 Java 没有无符号 byte 变量,因此虽然二进制是正确的,但您必须转换为更宽的类型才能获得正值。位掩码 b & 0xff 将为您扩大为 int 并恢复“无符号”值。

关于问题 1,如果您使用问题 2 的答案,映射将起作用。在大多数数组的 JNA 函数映射中,您可以通过将 byte[] 数组作为参数来简化此操作。但是,JNA 需要专门为回调映射的类型,因此不包括原始数组,因此首选 Pointer 方法。