Passing Bitmap over JNI

5,655 views
Skip to first unread message

RangaRao

unread,
Jan 1, 2010, 12:35:56 AM1/1/10
to android-ndk
Hi All,

I have native C++ library which decodes the picture and provided the
pixel array [unsigned short *mpixelarry]. The image returned by this
class is 16bpp color depth and having 5:6:5 pixel format.

Now I need to pass these Pixels to Android App where I am using canvas
to draw.
Here I am planning to use
canvas.drawBitmap(_myBitmap, pos_X, pos_Y, null);

Now the problem is -> I need to fill _myBitmap[in Java] with the
mpixelarry[from C++ Library].

But as am newbie to Android and JNI and Graphics....... Not very sure
how to proceed here.

Q1: mpixelarry I am getting from C++ library , is it compatible with
myBitmap?
Q2: Can I copy the pixels directly on to Bitmap?will it work.?are they
compatible ?
Q3:What is the Best way to pass the Pixel array from jni to JAVA.i.e
shall i have to create the myBitmap in Java and pass it to JNI
function and fill it with copyPixelsToBuffer API in JNI
or
Pass the bare Pixel array as it is from JNI to Java and do the stuff
in Java.

I had come across some threads, which are discussed on the same
subject, but could not follow them.[
http://groups.google.com/group/android-ndk/browse_thread/thread/a56eb182f70d2c0f

http://groups.google.com/group/android-ndk/browse_thread/thread/03cb3bc771fd3a1d
]

Q4: Can I get a sample piece of code to do this stuff.
Q5: Is the method I am following good[in performance perspective] or
do I need to look into OpenGL texture as suggested in the above
threads.


Thank you for your support

UKLooney

unread,
Jan 1, 2010, 9:52:31 AM1/1/10
to android-ndk
Hi, I do something like this-

On the java side:

Bitmap screen = Bitmap.createBitmap(width,height,
Bitmap.Config.RGB_565);
ShortBuffer bufferAsShort = ByteBuffer.allocateDirect(width * height *
2).asShortBuffer(); // allocateDirect is important

and in a main graphic thread loop between the surface's lock and
unlock:

bufferAsShort.position(0); // rewind the buffer to the start
mainScreen.copyPixelsFromBuffer(bufferAsShort); // copy the buffer
inside the bitmap
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY); // scaleX = scaleY = 1.0 for no
scaling
canvas.drawBitmap(mainScreen, matrix, null); // copy the bitmap into
the canvas


on the JNI side, I send the bufferAsShort reference to get the buffer
pointer, here's an example:

extern "C"
jint Java_org_abc_Test1_getBufferAsShort( JNIEnv* env, jobject thiz,
jobject bufferAsShort, jint width, jint height) {

jshort* buffer = (jshort*) (env)->GetDirectBufferAddress
(bufferAsShort);
// then you can mess with the buffer pointer to populate it with some
bitmap data

}

On Jan 1, 5:35 am, RangaRao <sujatha.gul...@gmail.com> wrote:
> Hi All,
>
> I have native C++ library which decodes the picture and provided the
> pixel array [unsigned short *mpixelarry]. The image returned by this
> class is 16bpp color depth and having 5:6:5 pixel format.
>
> Now I need to pass these Pixels to Android App where I am using canvas
> to draw.
> Here I am planning to use
> canvas.drawBitmap(_myBitmap, pos_X, pos_Y, null);
>
> Now the problem is -> I need to fill  _myBitmap[in Java]  with the
> mpixelarry[from C++ Library].
>
> But as am newbie to Android and JNI and Graphics....... Not very sure
> how to proceed here.
>
> Q1: mpixelarry I am getting from C++ library , is it compatible with
> myBitmap?
> Q2: Can I copy the pixels directly on to Bitmap?will it work.?are they
> compatible ?
> Q3:What is the Best way to pass the Pixel array from jni to JAVA.i.e
> shall i have to create the myBitmap in Java and pass it to JNI
> function and fill it with   copyPixelsToBuffer API in JNI
>              or
> Pass the bare Pixel array as it is from JNI to Java and do the stuff
> in Java.
>
> I had come across some threads, which are discussed on the same

> subject, but could not follow them.[http://groups.google.com/group/android-ndk/browse_thread/thread/a56eb...
>
> http://groups.google.com/group/android-ndk/browse_thread/thread/03cb3...

Message has been deleted

Menion

unread,
Jan 2, 2010, 6:41:36 AM1/2/10
to android-ndk
Hi,
unfortunately I have no answers to your questions, but I also have
some question that are similar to yours (so i don't want to start new
thread).

my problem:
- I'm painting map tiles onto screen (tiles are 120 x 120px -
14400px)
- from file with tiles I obtain
1. palette - array of int int[256] - 256 colors
2. image data, deflated by zlib, after decopress (by Inflater) i
receive 14400b array of byte[], that contain indexes of colors in
color array

currently i'm not using JNI so to create Bitmap I use this code:
[code]
// variables
private byte[] imageBuffer = new byte[120 * 120];
private int[] imageData = new int[120 * 120];

// part of code that create image
byte[] buffer = new byte[4];
is.read(buffer, 0, 4);
int size = UtilsIO.readInt(buffer, 0, 4); // get size of compressed
image data

// load and decompress data
buffer = new byte[size];
is.read(buffer, 0, size);
Inflater inflater = new Inflater();
inflater.setInput(buffer);
inflater.inflate(imageBuffer);

// 12 ms / image - stupid and very slow cycle to fill image data
with right colors
for (int i = 0; i < 14400; i++) {
imageData[i] = palette[imageBuffer[i] & 0xFF];
}

Bitmap bitmap = Bitmap.createBitmap(imageData, 120, 120,
Bitmap.Config.RGB_565);
[/code]

- so, after loading image data, I have to create new array filled
with right color for every pixel. This is very slow (cycle with 14400
computes for every image). I'm testing it on motorola milestone and
cause of big resolution, I need around 40 images to cover whole
screen. Because this is map application, so you move with tiles, this
method is very slow. Because I'm not much familiar with C++, I'm
asking if anyone have any idea how to make it faster, probably with
using of JNI.

thank you very much for answers and hope, that you RangaRao, will
find answer on your problem as well.
Menion

UKLooney

unread,
Jan 3, 2010, 8:18:38 AM1/3/10
to android-ndk
Drawing 40 images which fill the screen should be just about
achievable if using OpenGL. Another option would be to use a native
routine to pull the 40 images together into a single bitmap and pass
that back to be draw to the screen.

Menion

unread,
Jan 4, 2010, 4:00:42 AM1/4/10
to android-ndk
Thanks for reply UKLooney,
but i have no problem to draw 40 images in View.draw() method. I
have problem with speed of loading this images. When i load image
directly from disk, it takes about 3ms, so moving with map is very
fluent. But in above described function, where i'm doing this "for
(int i = 0; i < 14400; i++) {}", loading takes too much of time and
cpu. So i want to know, if exist any method, how to create images
(Bitmap) from these dats (256 int array palette and 14400 bytes array
pointing to palette - probably in native c) and post them back to
java.
Thanks

RangaRao

unread,
Jan 4, 2010, 11:01:44 PM1/4/10
to android-ndk
UKLooney,

Thank you for your suggestion. We are able to see the image now on the
Android emulator.

tony.xuan

unread,
Jan 5, 2010, 1:21:21 AM1/5/10
to android-ndk

you can do it like this:


extern "C"{
#include "test.h"
}

#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>

#define LOG_TAG "PicoDriveJNI"
#include <utils/Log.h>

#include <jni.h>
#include <JNIHelp.h>

#include <utils/SortedVector.h>
#include <ui/Surface.h>
#include <core/SkBitmap.h>
#include <core/SkPixelRef.h>
#include "android_runtime/AndroidRuntime.h"

#include <dlfcn.h>

using namespace android;

#define gClassName "com/android/myfirstnative/Jni_Cross"

//
static jfieldID jfVideoBuffer;
static jfieldID jfNativeBitmap;
static jclass jclassBitmap;
static SkBitmap *pVideoBuffer;
static char *pVideoRam = NULL;
jclass mClass;


static int SayHello(JNIEnv *env, jclass clazz,jcharArray
Ary_Printout)
{
mClass = (jclass)env->NewGlobalRef(clazz);
jchar* Printout= env->GetCharArrayElements(Ary_Printout,0);
memcpy(Printout,"hello world",12);
jint temint = GetValue();
return temint;
// env->ReleaseArrayElements(Ary_Printout, Printout, 0);
}

//
extern "C" void CCallJavaFun(int x, int y)
{
JNIEnv *j_env = AndroidRuntime::getJNIEnv();
jclass gclazz = j_env->FindClass(gClassName);
jmethodID jMid = j_env->GetMethodID(gclazz, "JavaFun", "(II)V");
if(jMid == NULL)
{
return ;
}
j_env->CallVoidMethod(mClass,jMid,x,y);
}


static void Set_ScrBitmap(JNIEnv *env, jclass clazz,jint w,jint h)
{

jclass gclazz = env->FindClass(gClassName);
jfVideoBuffer = env->GetFieldID(gclazz, "g_MapBitmap", "Landroid/
graphics/Bitmap;");

jclassBitmap = env->FindClass("android/graphics/Bitmap");
jfNativeBitmap = env->GetFieldID(jclassBitmap, "mNativeBitmap",
"I");

jclass jvb = (jclass)env->GetObjectField(clazz, jfVideoBuffer);

if ( jvb == NULL ) {
LOGE("Can't get mVideoBuffer");
return ;
}

pVideoBuffer = (SkBitmap *)env->GetIntField(jvb, jfNativeBitmap);

if ( pVideoBuffer == NULL )
{

LOGE("Can't get mVideoBuffer");
return;
}
pVideoRam = (char*) pVideoBuffer->getPixels();
if ( pVideoRam == NULL ) {
pVideoBuffer->allocPixels();
pVideoRam = (char*) pVideoBuffer->getPixels();
if ( pVideoRam == NULL ) {
LOGE("Can't get Video RAM");
return ;
}
}
refresh(pVideoRam);

}
/**** Native android method register ****/
static JNINativeMethod gMethods[] = {
{ "SayHello", "([C)I", (void *)SayHello },
{ "Set_ScrBitmap", "(II)V", (void *)Set_ScrBitmap},
};

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv *env;
if ( vm->GetEnv((void **)&env, JNI_VERSION_1_6) ) return JNI_ERR;

jclass clazz = env->FindClass(gClassName);
env->RegisterNatives(clazz, gMethods, NELEM(gMethods));

return JNI_VERSION_1_6;
}

void JNI_OnUnload(JavaVM* vm, void* reserved)
{
JNIEnv *env;
if (vm->GetEnv((void **)&env, JNI_VERSION_1_6)) return;
jclass cls = env->FindClass(gClassName);
env->UnregisterNatives(cls);
}

so ,you can get the buffer of the bitmap created by java through c/c+
+ code,here the buffer is
:
pVideoBuffer = (SkBitmap *)env->GetIntField(jvb, jfNativeBitmap);
pVideoRam = (char*) pVideoBuffer->getPixels();

then fill the buffer [pVideoRam] as you like.

any questions? please feel free to contact me.

Reply all
Reply to author
Forward
0 new messages