Java – JNI : Bitmap from unsigned char* always null

JNI : Bitmap from unsigned char* always null… here is a solution to the problem.

JNI : Bitmap from unsigned char* always null

I want to pass an image (via jni) from C++ to an android application. I started with an unsigned char* array. There is no corruption in this array; I can even save it to a ppm file and display it correctly on my laptop.

I then use this function to convert it to jByteArray:

jbyteArray imgByte=as_byte_array(env,imgRaw,img.getRawImageSize());
...
jbyteArray as_byte_array(JNIEnv *env, unsigned char* buf, int len) {
    jbyteArray array = env->NewByteArray (len);
    env->SetByteArrayRegion (array, 0, len, reinterpret_cast<jbyte*>(buf));
    return array;
}

After that, I send this jByteArray to the java side. This variable is populated correctly, as I can see when I print its hexadecimal value on LogCat:

07-01 18:02:45.941    7017-8238/com.myapp.myapp W/C++ side﹕  798a95798b9677889371838d6b7d8664757e5d6e7860717b5e...
07-01 18:02:46.941    7017-8238/com.myapp.myapp W/Java side﹕ 798a95798b9677889371838d6b7d8664757e5d6e7860717b5e...

The final step is to display it on the ImageView. To do this, I made the following code (taken from another question about SO

):

public void setImageViewWithByteArray(final ImageView view, byte[] data) {
    final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (bitmap==null) {
                Log.e(TAG,"Bitmap is NULL!");
                view.setImageResource(R.drawable.abc_btn_radio_material);
            }
            else {
                view.setImageBitmap(bitmap);
            }
        }
    });
}

However, the bitmap variable is always null. What exactly am I doing wrong? Is there a way to debug decodeByteArray?

Solution

BitmapFactor.decodeByteArray is used to decode compressed image data, such as the contents of PNG files.

If your byte array contains uncompressed RGB data, you can create a mutable Bitmap with the correct width and height, and then use Bitmap.setPixels Set the pixel. However, setPixels takes an integer array with 32-bit ARGB values, and from your logs, your byte array appears to contain 3 bytes of RGB data per pixel.

So you need to create an int array, then process your byte array and write an int value to an int array of each byte triplet, for example:

intArray[i] = 0xff000000 |
    (((int)data[i*3] & 255) << 16) | (((int)data[i*3+1] & 255) << 8) | ((int)data[i*3+2] & 255);

Then pass it to setPixels. Or you can do this on the JNI side and return a jintArray.

Related Problems and Solutions