我有一个小的JNI方法从屏幕上检索像素。该方法从Java接收ByteBuffer,并根据此问题how to write and read from bytebuffer passing from java to jni以C ++编写。
虽然这确实有效,但我注意到我写的第一个字节不正确,但其他字节是:
启动时输入长度为3 000000000239F238
颜色是202,97,79
在java中读取的值:-54,97,79
这是我程序的输出。
C ++代码:
JNIEXPORT void JNICALL Java_capturePixel(JNIEnv * env, jobject clz, jobject buffer)
{
jbyte* bufferStart = static_cast<jbyte*>(env->GetDirectBufferAddress(buffer));
jlong inputLength = env->GetDirectBufferCapacity(buffer);
HDC hScreenDC = GetDC(nullptr);
std::cout << "Input length is " << inputLength << " at start " << &bufferStart << std::endl;
COLORREF pixel = GetPixel(hScreenDC, 100, 20);
int r = GetRValue(pixel);
int g = GetGValue(pixel);
int b = GetBValue(pixel);
std::cout << "Color is " << r << ", " << g << ", " << b << std::endl;
bufferStart[0] = r;
bufferStart[1] = g;
bufferStart[2] = b;
}
我的Java代码(实际上是Kotlin):
val r = buffer.get()
val g = buffer.get()
val b = buffer.get()
println("values read in java: $r, $g, $b")
为什么第一个字节错误?我假设它与它的标志有关?但话又说回来,为什么其他人没有错呢?我不确定为什么会这样。
答案 0 :(得分:2)
正如Richard在评论中提到的那样,它与字节的符号有关。巧合的是,其他两个值是正确的,因为它们不超过127; RGB是无符号的,范围为0-255,而有符号字节的范围为-128到127。
缓冲区中的字节是正确的,但java buffer.get()
读取它已签名。
解决此问题的方法是使用读取的字节调用Byte.toUnsignedInt(...)(Java API)。
或者,您可以在Kotlin中创建扩展方法:
fun Byte.toUnsigned(): Int = this.toInt() and 0xff
然后您可以使用它来调用缓冲区上的get():
val r = buffer.get().toUnsigned()
val g = buffer.get().toUnsigned()
val b = buffer.get().toUnsigned()