Creating bitmap from Framebuffer byte array through JNI BitmapFactory

1,399 views
Skip to first unread message

Ali Helmy

unread,
Sep 28, 2013, 6:27:50 PM9/28/13
to andro...@googlegroups.com
I am trying to create a bitmap screenshot from my opengl framebuffer to share through an intent with ACTION_SEND

The following is my code:

  size_t size = w * h * 4;
  uint8_t *pixels = new uint8_t[size];
  glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  jobject jbitmap = 0;

  if(pixels != 0) {
    JNIEnv * env = GetEnv(state_->activity->vm);

    //create the jbyte array and fill in with the pixel data
    int byte_array_length = w * h;
    Log("byte array length = %d", byte_array_length);
    jbyteArray byte_array = env->NewByteArray(byte_array_length);
    env->SetByteArrayRegion(byte_array, 0, byte_array_length, (jbyte *)pixels);

    //get the BitmapFactory class
    jclass bitmap_factory_class = loadExternalClass("android/graphics/BitmapFactory");
    jmethodID decode_byte_array_method = env->GetStaticMethodID(bitmap_factory_class,
        "decodeByteArray", "([BII)Landroid/graphics/Bitmap;");
   
    //get the bitmap itself
    jbitmap = env->CallStaticObjectMethod(bitmap_factory_class, decode_byte_array_method,
        byte_array, 0, byte_array_length);
   
    env->DeleteLocalRef(byte_array);
  }

  if(jbitmap == 0) {
    Log("Could not create image from framebuffer to share");
  }


It looks like a load of crap, but in reality, all its doing is just loading the JNI BitmapFactory class, loading its decodeByteArray method, loading a JNI byteArray object with the pixel data and then calling the following alternative Java code

BitmapFactory.decodeByteArray(byte_array, 0, byte_array_length); //params: (array, offset, length)


However, the jbitmap object that is supposed to hold the image is always returning as 0

I have verified the pixels array read in by glReadPixels is valid and fine

What am I missing? Thanks a lot

limelect

unread,
Sep 29, 2013, 10:47:38 AM9/29/13
to andro...@googlegroups.com
I do not know if it helps but i used 
 this code 10 minutes ago and it works great

בתאריך יום ראשון, 29 בספטמבר 2013 01:27:50 UTC+3, מאת Ali Helmy:

a1

unread,
Sep 29, 2013, 1:30:14 PM9/29/13
to andro...@googlegroups.com

It looks like a load of crap, but in reality, all its doing is just loading the JNI BitmapFactory class, loading its decodeByteArray method, loading a JNI byteArray object with the pixel data and then calling the following alternative Java code

BitmapFactory.decodeByteArray(byte_array, 0, byte_array_length); //params: (array, offset, length)


However, the jbitmap object that is supposed to hold the image is always returning as 0

This is decoder call - that is this method try to decode JPEG or PNG (or other supported format) from passed byte array. You should allocate bitmap (see: Bitmap.createBitmap) and then fill it either with setPixels java method or with AndroidBitmap native API (see android/bitmap.h and function AndroidBitmap_lock/AndroidBitmap_unlock).

--
Bart

Ali Helmy

unread,
Sep 29, 2013, 6:04:46 PM9/29/13
to andro...@googlegroups.com
Thank you both for your suggestions. I now understand it a bit better and see where I was going wrong

-- 
Cheers,
Ali Helmy
--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-ndk...@googlegroups.com.
To post to this group, send email to andro...@googlegroups.com.
Visit this group at http://groups.google.com/group/android-ndk.
For more options, visit https://groups.google.com/groups/opt_out.

a1

unread,
Sep 30, 2013, 5:26:23 AM9/30/13
to andro...@googlegroups.com


W dniu poniedziałek, 30 września 2013 00:04:46 UTC+2 użytkownik Ali Helmy napisał:
Thank you both for your suggestions. I now understand it a bit better and see where I was going wrong
One more thing because I forgot to mention it and it's undocumented. If you would like to use AndroiBitmap native API to set pixels (with lock/unlock) be aware that android bitmaps keeps data in premultiplied format and with lock/unlock you get access to raw bitmap data - so if your framebuffer is translucent you have to premultiply it manually. 

--
Bart
Reply all
Reply to author
Forward
0 new messages