来自 Oracle 的 JNI 函数文档
https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#GetDirectBufferAddress
获取直接缓冲区地址
void* GetDirectBufferAddress(JNIEnv* env, jobject buf);
获取并返回内存区域的起始地址
由给定的直接 java.nio.Buffer 引用。
这个函数允许本地代码访问相同的内存区域
Java 代码可以通过缓冲区对象访问。链接:
JNIEnv 接口函数表中的索引 230。参数:
env:JNIEnv 接口指针
buf:一个直接的 java.nio.Buffer 对象(不能为 NULL) RETURNS:
返回被引用的内存区域的起始地址
缓冲。如果内存区域未定义,则返回 NULL,如果给定
对象不是直接java.nio.Buffer,或者如果JNI直接访问
此虚拟机不支持缓冲区。自:
JDK/JRE 1.4
我用这个 C++ 代码进行了测试:
static char framebuf[100];
JNIEXPORT void JNICALL Java_javaapplication45_UseByteBuffer_readBuf
(JNIEnv *env, jobject usebb, jobject bb) {
void *addr = env->GetDirectBufferAddress(bb);
framebuf[0] = 77;
memcpy(addr,framebuf,100);
}
还有这个 Java 代码:
public class UseByteBuffer {
public native void readBuf(ByteBuffer bb);
}
...
public static void main(String[] args) {
System.load("/home/shackle/NetBeansProjects/usebb/dist/Debug/GNU-Linux-x86/libusebb.so");
ByteBuffer bb = ByteBuffer.allocateDirect(100);
new UseByteBuffer().readBuf(bb);
byte first_byte = bb.get(0);
System.out.println("first_byte = " + first_byte);
}
它打印了 first_byte=77,表明它正确复制了数据。
更新
ImageIO.read() 不会只接受任何字节集,它必须采用已安装的 ImageReader 可以识别的格式,例如 JPEG 或 PNG。
这是一个将 (3 byte r,g,b )bytes 的原始图像转换为图像的示例
int width = 256;
int height = 256;
ByteBuffer bb = ByteBuffer.allocateDirect(height*width*3);
byte[] raw = new byte[width * height * 3];
bb.get(raw);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
DataBuffer buffer = new DataBufferByte(raw, raw.length);
SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 3, width * 3, new int[]{0,1,2});
Raster raster = Raster.createRaster(sampleModel, buffer, null);
image.setData(raster);
更新 2
对于 BGR32,我相信这会更接近:
ByteBuffer imageData = ByteBuffer.allocateDirect(height * width * 4);
byte[] raw = new byte[width * height * 4];
imageData.get(raw);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
DataBuffer buffer = new DataBufferByte(raw, raw.length);
SampleModel sampleModel = new ComponentSampleModel(
DataBuffer.TYPE_BYTE, width, height, 4, width * 4,
new int[]{2,1,0} // Try {1,2,3}, {3,2,1}, {0,1,2}
);
Raster raster = Raster.createRaster(sampleModel, buffer, null);
image.setData(raster);
请注意我评论的地方,我怀疑您可能需要在 ComponentSampleModel 构造函数的第三个参数中试验 bandOffsets 数组来修复颜色模型。
更新 3
可以通过使用 BufferedImage.copyData() 到 WritableRaster 而不是使用 getRaster() 来重用 sampleModel 从图像中获取数据。
SampleModel sampleModel = new ComponentSampleModel(
DataBuffer.TYPE_BYTE, width, height, 4, width * 4,
new int[]{2, 1, 0}
);
...
BufferedImage newImage = ImageIO.read(new File("test.png"));
byte newRaw[] = new byte[height*width*4];
DataBuffer newBuffer = new DataBufferByte(newRaw, newRaw.length);
WritableRaster newRaster = Raster.createWritableRaster(sampleModel, newBuffer, null);
newImage.copyData(newRaster);