将数据从非托管内存指针复制到 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);
将内存中的位置复制到位图数组。
- 我不确定我的界面
RSPreviewDataCallback
签名是否正确
- 不知道有没有JNA相当于把内存位置复制到字节数组
关于问题 2,从 Pointer
获取字节数组的 JNA 调用是 Pointer.getByteArray()
。所以你可以使用 imageData.getByteArray(0, imagewidth * imageheight)
.
从指针中获取字节
请注意 Java 没有无符号 byte
变量,因此虽然二进制是正确的,但您必须转换为更宽的类型才能获得正值。位掩码 b & 0xff
将为您扩大为 int
并恢复“无符号”值。
关于问题 1,如果您使用问题 2 的答案,映射将起作用。在大多数数组的 JNA 函数映射中,您可以通过将 byte[]
数组作为参数来简化此操作。但是,JNA 需要专门为回调映射的类型,因此不包括原始数组,因此首选 Pointer
方法。
我有一个 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);
将内存中的位置复制到位图数组。
- 我不确定我的界面
RSPreviewDataCallback
签名是否正确 - 不知道有没有JNA相当于把内存位置复制到字节数组
关于问题 2,从 Pointer
获取字节数组的 JNA 调用是 Pointer.getByteArray()
。所以你可以使用 imageData.getByteArray(0, imagewidth * imageheight)
.
请注意 Java 没有无符号 byte
变量,因此虽然二进制是正确的,但您必须转换为更宽的类型才能获得正值。位掩码 b & 0xff
将为您扩大为 int
并恢复“无符号”值。
关于问题 1,如果您使用问题 2 的答案,映射将起作用。在大多数数组的 JNA 函数映射中,您可以通过将 byte[]
数组作为参数来简化此操作。但是,JNA 需要专门为回调映射的类型,因此不包括原始数组,因此首选 Pointer
方法。