Reprinted from http://www.ibm.com/developerworks/cn/opensource/tutorials/os-androidndk/section5.html
First ,we will use android/bitmap.h,so the lowest version is Android 2.2(Froyo).
1.Transfer the bitmap object.
ibmphotophun.c:
/* * ibmphotophun.c * * Author: Frank Ableson * Contact Info: fableson@msiservices.com */ #include <jni.h> #include <android/log.h> #include <android/bitmap.h> #define LOG_TAG "libibmphotophun" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) typedef struct { uint8_t alpha; uint8_t red; uint8_t green; uint8_t blue; } argb; /* convertToGray Pixel operation */ JNIEXPORT void JNICALL Java_com_wzh_test_NDKTestActivity_convertToGray(JNIEnv * env, jobject obj, jobject bitmapcolor,jobject bitmapgray) { AndroidBitmapInfo infocolor; void* pixelscolor; AndroidBitmapInfo infogray; void* pixelsgray; int ret; int y; int x; LOGI("convertToGray"); if ((ret = AndroidBitmap_getInfo(env, bitmapcolor, &infocolor)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } if ((ret = AndroidBitmap_getInfo(env, bitmapgray, &infogray)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } LOGI("color image :: width is %d; height is %d; stride is %d; format is %d;flags is %d", infocolor.width,infocolor.height,infocolor.stride,infocolor.format,infocolor.flags); if (infocolor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { LOGE("Bitmap format is not RGBA_8888 !"); return; } LOGI("gray image :: width is %d; height is %d; stride is %d; format is %d;flags is %d", infogray.width,infogray.height,infogray.stride,infogray.format,infogray.flags); if (infogray.format != ANDROID_BITMAP_FORMAT_A_8) { LOGE("Bitmap format is not A_8 !"); // return; } if ((ret = AndroidBitmap_lockPixels(env, bitmapcolor, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } if ((ret = AndroidBitmap_lockPixels(env, bitmapgray, &pixelsgray)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } // modify pixels with image processing algorithm for (y=0;y<infocolor.height;y++) { argb * line = (argb *) pixelscolor; uint8_t * grayline = (uint8_t *) pixelsgray; for (x=0;x<infocolor.width;x++) { grayline[x] = 0.3 * line[x].red + 0.59 * line[x].green + 0.11*line[x].blue; } pixelscolor = (char *)pixelscolor + infocolor.stride; pixelsgray = (char *) pixelsgray + infogray.stride; } LOGI("unlocking pixels"); AndroidBitmap_unlockPixels(env, bitmapcolor); AndroidBitmap_unlockPixels(env, bitmapgray); }
LOGI 和 LOGE 宏對 Logging 工具進行調用,並且在功能上分別相當於 Android SDK 中的 Log.i() 和 Log.e()。具有 typedef struct 關鍵字的 argb 數據類型支持 C 代碼評估以 32 位整數存儲的單個像素的 4 個數據元素。3 個包含語句為 C 編譯器提供必要的聲明,以進行 jni 粘合、日志記錄和位圖處理。
現在可以實現一些圖像處理例程了,但是在我們檢查代碼之前,您需要了解 JNI 函數的命名約定。
當 Java 代碼調用本機函數時,它將函數名稱映射到一個展開或修飾函數,該函數由 JNI 共享庫導出。下面是約定:Java_fully_qualified_classname_functionname。
例如,convertToGray 函數在 C 代碼中實現為 Java_com_msi_ibm_ndk_IBMPhotoPhun_convertToGray。
JNI 函數的前兩個參數包含一個 JNI 環境指針和調用類對象實例。有關 JNI 的更多信息,請參見 參考資料 部分。
構建庫非常簡單。打開終端(或 DOS)窗口並將目錄更改到存儲這些文件的 jni 文件夾。確保路徑中有 NDK 並執行 ndk-build 腳本。此腳本包含構建庫所需的所有粘合代碼。生成的庫放置在與 jni 文件夾級別相同的 libs 文件夾(例如,<project folder>/libs/)。
Eclipse 的 ADT 插件打包了 Android 應用程序后,會自動包含和傳輸庫文件。會為每個支持的硬件平台都生成一個庫文件。在運行時加載正確的庫。
此函數有兩個調用 Java 代碼的參數:ARGB 格式中的彩色 Bitmap 和接收彩色圖像的灰度版本的 8 位灰度 Bitmap。下面是代碼的簡單介紹:
AndroidBitmapInfo結構,在 bitmap.h 中定義,有助於了解Bitmap對象。AndroidBitmap_getInfo函數,在 jnigraphics 庫中,獲取有關具體Bitmap對象的信息。- 下一步是確保傳入到
convertToGray函數的位圖是想要的格式。 AndroidBitmap_lockPixels函數鎖定圖像數據,這樣您就可以直接在數據上執行操作。AndroidBitmap_unlockPixels函數解鎖之前鎖定的像素數據。這些函數應該被稱為“鎖定/解鎖對”。
Android.mk:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ibmphotophun LOCAL_SRC_FILES := ibmphotophun.c LOCAL_LDLIBS := -llog -ljnigraphics include $(BUILD_SHARED_LIBRARY)
其中,該 makefile(片段)指示 NDK:
- 將 ibmphotophun.c 源文件編譯到共享庫中。
- 命名共享庫。默認情況下,共享庫命名約定為 lib<modulename>.so。因此,在這里將生成文件命名為 libibmphotophun.so。
- 指定所需的 "input" 庫。共享庫依賴於兩個用於日志記錄(liblog.so)和 jni 圖形(libjnigraphics.so)的內置庫文件,日志記錄庫允許您為
LogCat添加條目,這在項目的開發階段很有用。圖形庫為使用 Android 位圖及其圖像數據提供例程。
libjnigraphics是從android 2.2開始引入的一個庫,在NDK中可以通過引用
bitmap.h進行使用。這個庫加快了NDK層訪問java層的bitmap數據的速度,同時也
降低了內存消耗(少了一個臨時中轉用的int array)
細看了下,這個庫實際上可以自己放到apk的lib下面進行調用。
這個庫實際上只導入了三個外部函數,對bitmap的訪問進行了封裝
GraphicsJNI::getNativeBitmap
SkBitmap::lockPixels
SkBitmap::unlockPixels
這三個函數在目前所有版本的android里面都有。因此libjnigraphics.so實際上可以在目前所有版本的android中使用。只是低於android 2.2的版本,必須自己將 libjnigraphics.so打包進apk。但是需要注意的是目前新版ndk里面附帶的libjnigraphics.so不行,那個只是個空殼。可以自己從比較老的版本的NDK里面拿出來使用,或者自己從android 2.2及以上的image里摳出來,具體路徑/system/lib/libjnigraphics.so。 然后由於是打包進apk的so。所以需要自己在源碼里面顯示調用 system.loadlibrary(jnigraphics);
ibmphotophun.c 源文件包含一些 C 包含語句和 argb 類型(對應於 Android SDK 中的彩色數據類型)的定義。清單 4 顯示了沒有圖像例程的 ibmphotophun.c,圖像例程將在下一個清單中展示。
NDKTestActivity.java:
package com.wzh.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.os.Bundle; import android.widget.ImageView; import android.widget.TextView; public class NDKTestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bitmap src=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); Bitmap dst=Bitmap.createBitmap(src.getWidth(), src.getHeight(), Config.ARGB_8888); convertToGray(src,dst); ImageView iv = new ImageView(this); iv.setImageBitmap(dst); setContentView(iv); } public native void convertToGray(Bitmap src,Bitmap dst); static { System.loadLibrary("ibmphotophun"); } }
.......
