JNI层向Java层传递bitmap

在图像处理SDK像安卓平台转化时,因为使用C/C++开发,所有对外接口需要封装成JNI接口,图像数据的传递可以采用裸数据的形式,直接将传回图像像素值数组,但是也会遇到需要传回bitmap,这时候可以采用两种方案。

一、Java预先creatBitmap,然后将jobject bitmap作为JNI接口的参数,传给JNI层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
AndroidBitmapInfo info;
int result = AndroidBitmap_getInfo(env, bitmap, &info);//获取java层创建的bitmap图像信息
if (result != ANDROID_BITMAP_RESULT_SUCCESS)
{
    LOGD("AndroidBitmap_getInfo failed, result: %d", result);
    return (jint)ERROR_INVALID_IMAGE;
}
LOGD("bitmap width: %d, height: %d, format: %d, stride: %d", info.width, info.height,
             info.format, info.stride);
       
unsigned char *srcData = NULL;
AndroidBitmap_lockPixels(env, bitmap, (void**)&srcData);//锁定图像像素
for(int i=0;i<info.width*info.height;i++)
{
    srcData[4*i] = imgData[3*i];    //这里的imgData指的就是存放了像素值的数据
    srcData[4*i+1] = imgData[3*i+1];
    srcData[4*i+2] = imgData[3*i+2];
    srcData[4*i+3] = (unsigned char)255;
}
AndroidBitmap_unlockPixels(env, bitmap);//释放图像像素

该方案需要java层预先创建好一个bitmap,但实际情况可能是java层在调用接口前并不知道要创建多大尺寸的bitmap,这时可采用下面的方法。

二、JNI层回调Java的Bitmap类与方法creatBitmap,然后将jobject bitmap传出(比如直接return)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
jclass bitmapCls = env->FindClass("android/graphics/Bitmap");
jmethodID createBitmapFunction = env->GetStaticMethodID(bitmapCls,"createBitmap",                                                                
                 "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
jstring configName = env->NewStringUTF("ARGB_8888");
jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(
                                                            bitmapConfigClass, "valueOf",
                                 "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");

jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass,
                                                                   
                                                 valueOfBitmapConfigFunction,configName);

jobject bitmap = env->CallStaticObjectMethod(bitmapCls,
                                             createBitmapFunction,
                                             nOutWidth,
                                             nOutHeight, bitmapConfig);
       
unsigned char *resultBitmapPixels = NULL;
int ret;
if ((ret = AndroidBitmap_lockPixels(env, bitmap, (void**)&resultBitmapPixels)) < 0)
{
    LOGD("AndroidBitmap_lockPixels() failed ! error=%d", ret);  
}
int pixelsCount = nOutWidth * nOutHeight * 4;

for(int i=0;i<nOutWidth*nOutHeight;i++)
{
    resultBitmapPixels[4*i] = imgData[3*i];
    resultBitmapPixels[4*i+1] = imgData[3*i+1];
    resultBitmapPixels[4*i+2] = imgData[3*i+2];
    resultBitmapPixels[4*i+3] = (unsigned char)255;
}
AndroidBitmap_unlockPixels(env, bitmap);//最终得到的就是bitmap

ps:编译时Android.mk中LOCAL_LDLIBS := -llog -ljnigraphics,使用AndroidBitmap需要-ljnigraphics