Android NDK图形API篇
前言
我们知道,在游戏和多媒体领域,图形和图像的处理速度和性能至关重要,在Java层处理图形、图像速度又比较慢,不能满足实际的需要,这时候我们就可以借助原生图形API来让自己的游戏和多媒体应用表现更出色。

本篇重点介绍原生图形API的相关知识,并通过一些示例,让大家更好的掌握原生图形API的相关知识。

原生图形API
原生图形API的种类
l  JNI图形API也叫位图API

l  Open GL ES API

l  原生Window API

JNI图形API也叫位图API

需要引用的头文件
 #include <android/bitmap.h>需要引用的so库
 jnigraphics.soJNI图形API函数解析
 获取Bitmap对象信息
 int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo*info);enum AndroidBitmapFormat {
     ANDROID_BITMAP_FORMAT_NONE      = 0,
     ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
     ANDROID_BITMAP_FORMAT_RGB_565   = 4,
     ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
     ANDROID_BITMAP_FORMAT_A_8       = 8,
 };typedef struct {
     uint32_t    width;
     uint32_t    height;
     uint32_t    stride;
     int32_t     format;
     uint32_t    flags;      // 0 for now
 } AndroidBitmapInfo;


 

函数解析

env,指JNIEnv结构体指针

jbitmap,指android的Bitmap对象

info,指AndroidBitmapInfo结构体指针

如果函数调用成功,返回0,否则返回-1

示例代码

AndroidBitmapInfo info;
int result=AndroidBitmap_getInfo(env,bitmap,&info);
锁定Bitmap像素缓存
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
函数解析

env,指JNIEnv结构体指针

jbitmap,指android的Bitmap对象

addrPtr,指指向jbitmap对象的像素数据指针

如果函数调用成功,返回0,否则返回-1

示例代码

int32_t *buffer=0;
result=AndroidBitmap_lockPixels(env,bitmap,(void**)&buffer);

解锁Bitmap像素缓存
int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
函数解析

env,指JNIEnv结构体指针

jbitmap,指android的Bitmap对象

如果函数调用成功,返回0,否则返回-1

示例代码

AndroidBitmap_unlockPixels(env,bitmap);
JNI图形API示例
 extern "C"
 JNIEXPORT void JNICALL
 Java_com_kgdwbb_jnistudy_MainActivity_render(JNIEnv* env, jobject thiz,jobject bitmap,jobject bitmap2){
     int32_t *buffer=0;
     AndroidBitmapInfo info;
     int result=AndroidBitmap_getInfo(env,bitmap,&info);    result=AndroidBitmap_lockPixels(env,bitmap,(void**)&buffer);
    int32_t *data=0;
    result=AndroidBitmap_lockPixels(env,bitmap2,(void**)&data);
     long len= sizeof(int)*info.width*info.height;
     //memcpy(buffer,data,len);
     memmove(buffer,data,len);
     AndroidBitmap_unlockPixels(env,bitmap2);
    AndroidBitmap_unlockPixels(env,bitmap);
 }

其中bitmap是一个动态生成的bitmap,没有位图数据,bitmap2是一个真实的图像bitmap,这个例子要做的就是把bitmap2的位图数据复制到bitmap的位图数据所指向的地址空间里面。

Open GL ES API

需要引用的头文件
 Open GL ES 1.x头文件#include <GLES/gl.h>
#include <GLES/glext.h>
Open GL ES 2.x头文件
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
需要引用的so库
 Open GL ES 1.x库文件GLESV1_CM.so
Open GL ES 2.x库文件
GLESv2.so
GLSurfaceView


如果原生代码需要使用Open GL ES的相关函数来进行view的渲染,在android端需要使用GLSurfaceView进显示渲染后的内容

Open GL ES API函数解析
关于Open GL ES API,由于这个函数库比较大,涉及的函数比较多,请大家参考专业的Open GL ES相关的书籍,这里就不再介绍了。

Open GL ES API示例
请大家参考Open GL ES的相关书箱或者官方教程

原生Window API

需要引用的头文件
 #include <android/native_window.h>#include<android/native_window_jni.h>
需要引用的so库
 android.so原生Window API函数解析
 从Surface对象中检索原生Window
 ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);

函数解析

env,指JNIEnv结构体的指针

suerface,指向android的Surface对象

如果函数调用成功,返回指向ANativeWindow的指针,否则返回NULL

获取原生Window实例中的引用
void ANativeWindow_acquire(ANativeWindow* window);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

这个函数的功能就是防止引用的surface对象被删除,获取一个指向surface对象的引用

释放原生Window实例中的引用
void ANativeWindow_release(ANativeWindow* window);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

这个函数的功能就是释放通过ANativeWindow_acquire函数获取的surface对象的引用

检索原生Window的信息
获取原生window的宽度
int32_t ANativeWindow_getWidth(ANativeWindow* window);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

如果调用成功,返回原生window的宽度,否则返回-1

获取原生window的高度
int32_t ANativeWindow_getHeight(ANativeWindow* window);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

如果调用成功,返回原生window的高度,否则返回-1

获取原生window的像素格式
int32_t ANativeWindow_getFormat(ANativeWindow* window);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

如果函数调用成功,返回原生window的像素格式,否则返回-1

设置原生window缓冲区的几何形状

int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
         int32_t width, int32_t height,int32_t format);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

width,设置原生window的宽度

height,设置原生window的高度

format,设置原生window的像素格式

如果函数调用成功,返回0,否则,返回-1

锁定原生Window的缓冲区

typedef struct ANativeWindow_Buffer {
     // The number ofpixels that are show horizontally.
     int32_t width;    // The number ofpixels that are shown vertically.
     int32_t height;    // The number of*pixels* that a line in the buffer takes in
     // memory.  This may be >= width.
     int32_t stride;    // The format of thebuffer.  One of WINDOW_FORMAT_*
     int32_t format;    // The actual bits.
     void* bits;
     
     // Do not touch.
     uint32_t reserved[6];
 } ANativeWindow_Buffer; 
int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer*outBuffer,
         ARect* inOutDirtyBounds);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

outBuffer,指向ANativeWindow_Buffer结构体的指针,

inOutDirtyBounds,指向ARect结构体的指针,这个参数为可选参数

如果函数调用成功,返回0,否则,返回-1

释放原生Window的缓冲区
int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);

函数解析

window,指通过ANativeWindow_fromSurface函数获取的ANativeWindow指针

如果函数调用成功,返回0,否则,返回-1

SurfaceView
在android层要想使用原生windowAPI,我们需要使用SurfaceView来和原生windowAPI配置,我们可以通过SurfaceView来获取原生windowAPI需要的surface对象

原生Window API示例

extern "C"
 JNIEXPORT void JNICALL
 Java_com_kgdwbb_jnistudy_MainActivity_render2(JNIEnv* env, jobject thiz,jobject surface,jobject bitmap){
     AndroidBitmapInfo info;
    AndroidBitmap_getInfo(env,bitmap,&info);
     int dataLen= sizeof(int) * info.width *info.height;    char *data=NULL;
     AndroidBitmap_lockPixels(env,bitmap,(void**)&data);
     AndroidBitmap_unlockPixels(env,bitmap);    ANativeWindow *window=ANativeWindow_fromSurface(env,surface);
 //    intwidth=ANativeWindow_getWidth(window);
 //    intheight=ANativeWindow_getHeight(window);
 //    intformat=ANativeWindow_getFormat(window);
 //   ANativeWindow_setBuffersGeometry(window,width,height,format);    ANativeWindow_acquire(window);
    ANativeWindow_BufferwindowBuffer;
    ANativeWindow_lock(window,&windowBuffer,NULL);    dataLen= sizeof(int)*windowBuffer.width*windowBuffer.height;
    if (windowBuffer.bits != NULL) {
         //memcpy(windowBuffer.bits,data, dataLen);
         if (windowBuffer.width == windowBuffer.stride) {
             memcpy(windowBuffer.bits, data, dataLen);
         } else {
             int offset=windowBuffer.stride-windowBuffer.width;
             for (int ii=0; ii <windowBuffer.height*2; ii++) {
                 char *srcPointer = data+ windowBuffer.width * ii*2;
                 char *dstPointer = ((char *)windowBuffer.bits) + windowBuffer.stride * ii*2;                memcpy(dstPointer,srcPointer, windowBuffer.stride*2);
             }
         }
     }    ANativeWindow_release(window);
    ANativeWindow_unlockAndPost(window);
 }

结束语
本篇介绍了android NDK三种原生图形API,各有所长,大家可以根据需要来选用,对于最强大最复杂的Open GL ES的内容,本篇暂时不作深入介绍,有兴趣的同学可以参考其它Open GL ES的专业书籍或教程来系统的学习。

Android NDK提供的这三种强大的图形API,让我们可以在游戏和多媒体领域充分发挥我们所长,设计和开发中精美的作品。

本篇文章只是抛砖引玉,大家如果想在图形图像领域有所成就,仅仅学习本篇文章是远远不够的。大家还需要在图形图像领域进行更深入的学习和研究。