JNI: чтение и запись в прямом буфере

У меня есть небольшой метод JNI для извлечения пикселя с экрана. Этот метод получает ByteBuffer от Java и записывается на C ++ в соответствии с этим вопросом, как писать и читать из байтового буфера, переходящего из java в jni .

Хотя это действительно работает, я заметил, что первый байт, который я пишу, неверен, но остальные:

Длина ввода 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 (на самом деле Котлин):

 val r = buffer.get() val g = buffer.get() val b = buffer.get() println("values read in java: $r, $g, $b") 

Почему первый байт ошибочен? Я предполагаю, что это связано с его знаком? Но опять же, почему другие не ошибаются? Я не знаю, почему это происходит.

Как упоминал Ричард в комментариях, это связано со знаком байта. Совпадение двух других значений верно, потому что они не выше 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()