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.so
JNI圖形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,讓我們可以在遊戲和多媒體領域充分發揮我們所長,設計和開發中精美的作品。
本篇文章只是拋磚引玉,大家如果想在圖形圖像領域有所成就,僅僅學習本篇文章是遠遠不夠的。大家還需要在圖形圖像領域進行更深入的學習和研究。