android平臺下基於ANativeWindow實現渲染bitmap影象
阿新 • • 發佈:2018-12-21
OpenGL ES 3.0學習實踐
概述
原生Window API
支援我們在ndk下
開發原生的繪製功能,後續的一些視訊渲染,包括相機採集預覽等都可以通過這些API
來實現,筆者今天通過幾個簡單的API來實踐一下native層
的繪製功能
配置環境
筆者Android Studio
配置的是android-ndk-r16b
版本,作業系統是ubuntu 16.05
繪製背景色
還是從最簡單的入手,開始嘗試繪製背景顏色,我們此次使用的方案是SurfaceView+ANativeWindow
的方式,基於之前的專案工程
先定義Java層的本地方法
:
/**
* @anchor: andy
* @date: 2018-11-13
* @description:
*/
public class NativeWindowSample {
static {
System.loadLibrary("native-window");
}
/**
* 繪製指定顏色背景
*
* @param surface
* @param color
*/
public native void drawColor(Object surface, int color);
/**
* 繪製指定顏色背景
*
* @param surface
* @param bitmap
*/
public native void drawBitmap(Object surface, Object bitmap);
}
配置CMakeLists.txt
檔案內容如下:
cmake_minimum_required(VERSION 3.4.1)
##官方標準配置
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -fno-exceptions -Wall")
add_library(native-window
SHARED
src/ main/cpp/native_window.cpp)
target_link_libraries(native-window
${OPENGL_LIB}
android
jnigraphics
log)
build.gradle
中的配置,這裡不贅述,比較簡單
在我們的子工程目錄src/main/cpp
下新建我們的native_window.cpp
和native_window.h
檔案:
來看看native_window.cpp
中drawColor
的實現:
void drawColor(JNIEnv *env, jobject obj, jobject surface, jint colorARGB) {
//分離ARGB
int alpha = (colorARGB >> 24) & 0xFF;
int red = (colorARGB >> 16) & 0xFF;
int green = (colorARGB >> 8) & 0xFF;
int blue = colorARGB & 0xFF;
int colorABGR = (alpha << 24) | (blue << 16) | (green << 8) | red;
//獲取目標surface
ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
//預設的是RGB_565
ANativeWindow_setBuffersGeometry(window, 640, 640, WINDOW_FORMAT_RGBA_8888);
ANativeWindow_acquire(window);
ANativeWindow_Buffer buffer;
ANativeWindow_lock(window, &buffer, NULL);
uint32_t *line = (uint32_t *) buffer.bits;
for (int y = 0; y < buffer.height; y++) {
for (int x = 0; x < buffer.width; x++) {
line[x] = colorABGR;
}
line = line + buffer.stride;
}
ANativeWindow_unlockAndPost(window);
//釋放視窗
ANativeWindow_release(window);
}
這裡要注意的就是,我們從Java層傳入的是32位的ARGB
的顏色,直接寫入我們的windowBuffer
,顏色顯示可能不正確,需要按照ANativeWindow_Buffer
指定的顏色順序作一次轉換
繪製一個灰色背景:
mNativeWindowSample.drawColor(mSurfaceView.getHolder().getSurface(), Color.GRAY);
繪製bitmap
直接繪製bitmap
也比較簡單,但是我們需要通過AndroidBitmap_lockPixels
方法獲取bitmap
對應的本地的資料的指標,通過這個指標來讀取對應的畫素資料,註釋也比較清楚
void drawBitmap(JNIEnv *env, jobject obj, jobject surface, jobject bitmap) {
//獲取bitmap的資訊,比如寬和高
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, bitmap, &info);
char *data = NULL;
//獲取bitmap對應的native指標
AndroidBitmap_lockPixels(env, bitmap, (void **) &data);
AndroidBitmap_unlockPixels(env, bitmap);
//獲取目標surface
ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
//這裡設定為RGBA的方式,總共是4位元組32位
ANativeWindow_setBuffersGeometry(window, info.width, info.height, WINDOW_FORMAT_RGBA_8888);
ANativeWindow_acquire(window);
ANativeWindow_Buffer buffer;
//鎖定視窗的繪圖表面
ANativeWindow_lock(window, &buffer, NULL);
//轉換為畫素點來處理
int32_t *bitmapPixes = (int32_t *) data;
uint32_t *line = (uint32_t *) buffer.bits;
for (int y = 0; y < buffer.height; y++) {
for (int x = 0; x < buffer.width; x++) {
line[x] = bitmapPixes[buffer.height * y + x];
}
line = line + buffer.stride;
}
//解鎖視窗的繪圖表面
ANativeWindow_unlockAndPost(window);
//釋放
ANativeWindow_release(window);
}
繪製一個bitmap物件
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.main, options);
mNativeWindowSample.drawBitmap(mSurfaceView.getHolder().getSurface(), bitmap);