转载请保留原文链接:http://blog.csdn.net/u010593680/article/details/41410289
附带宣传下参与的网站: 最爱明星网:http://zuiaimingxing.com/ 给自己的爱豆打call
最近的学习真的比较困难,因为学习了SDK开发项目后,做了一些简单的项目后,觉得在UI线程中加载较多图片时,总会出现卡顿的感觉,特别是手指滑动下拉时,这种卡顿更易察觉到,而java的结构化开发能力确实是很强大的,使用java开发确实是一件非常享受的事情,但是java在一些高密度的计算中是没有什么优势的,在享受内存自动回收时也会遇到一些不如意的事。任何语言或事物,总会有优缺点,这是java如此简单易用的一个副作用。所以为了不使java的副作用危害到开发者使用java,java产生了一种非常有吸引力的的技术JNI技术,这种技术可以让Java调用C/C++和其他的语言所写的程序。而这种技术也在android中得以支持--NDK, NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk,使用起来非常方便。
说了一堆的废话,接下来记录下自己最近所学习到的东西,可以说NDK重要的学习资料之一就是android的官方网站提供的资料,包括下载了NDK后,也能看到一些简单的使用了NDK的项目源码,这些源码能让我们知道android官方建议我们如何使用NDK,甚至可以用纯C/C++语言开发应用,但这并不是我感兴趣的,具体原因就不说了。
按照官方的使用方式还是比较简单的,这里写了一个用C语言提取照片灰度图的函数,并在java中调用
先写java代码
public class PhotoProcessingActivity extends Activity{
private Bitmap bmOriginal,bmGray;
private ImageView iv;
private Button btGray,btOpen;
static{
System.loadLibrary("PhotoProcessing");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.photo_processing_activity);
setup();
}
public void setup(){
iv = (ImageView) findViewById(R.id.showPhoto);
bmOriginal = ImageShare.mBitmap;
iv.setImageBitmap(bmOriginal);
btGray = (Button) findViewById(R.id.btGray);
btGray.setOnClickListener(onclick);
btOpen = (Button) findViewById(R.id.btOpen);
btOpen.setOnClickListener(onclick);
}
OnClickListener onclick = new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.btGray:
bmGray = Bitmap.createBitmap(bmOriginal.getWidth(), bmOriginal.getHeight(), Config.ALPHA_8);
grayPhoto(bmOriginal, bmGray);
iv.setImageBitmap(bmGray);
break;
case R.id.btOpen:
Intent intent = new Intent(PhotoProcessingActivity.this,
SurfaceProcessingActivity.class);
startActivity(intent);
break;
}
}
};
public native void grayPhoto(Bitmap bmOriginal,Bitmap bmGray);
}
使用javah工具得到头文件PhotoProcessingActivity.h并且添加处理图片所需的一些头文件,这些头文件都是NDK中的include中自带的,使用时可以把把该文件夹链接进去
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_photoprocessing_activity_PhotoProcessingActivity */
#include <android/bitmap.h>
#include <android/log.h>
#include <math.h>
#include <string.h>
#ifndef _Included_com_example_photoprocessing_activity_PhotoProcessingActivity
#define _Included_com_example_photoprocessing_activity_PhotoProcessingActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_PRIVATE
#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_PRIVATE 0L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_READABLE
#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_READABLE 1L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_WRITEABLE
#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_WRITEABLE 2L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_APPEND
#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_APPEND 32768L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_MULTI_PROCESS
#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_MULTI_PROCESS 4L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING
#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_AUTO_CREATE
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_AUTO_CREATE 1L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_DEBUG_UNBIND
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_DEBUG_UNBIND 2L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_NOT_FOREGROUND
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_NOT_FOREGROUND 4L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ABOVE_CLIENT
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ABOVE_CLIENT 8L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ALLOW_OOM_MANAGEMENT
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_WAIVE_PRIORITY
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_WAIVE_PRIORITY 32L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_IMPORTANT
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_IMPORTANT 64L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ADJUST_WITH_ACTIVITY
#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ADJUST_WITH_ACTIVITY 128L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_INCLUDE_CODE
#define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_INCLUDE_CODE 1L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_IGNORE_SECURITY
#define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_IGNORE_SECURITY 2L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_RESTRICTED
#define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_RESTRICTED 4L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_CANCELED
#define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_CANCELED 0L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_OK
#define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_OK -1L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_FIRST_USER
#define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_FIRST_USER 1L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DISABLE
#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DISABLE 0L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DIALER
#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DIALER 1L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SHORTCUT
#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SHORTCUT 2L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_LOCAL
#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
/*
* Class: com_example_photoprocessing_activity_PhotoProcessingActivity
* Method: grayPhoto
* Signature: (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap;)V
*/
/**
* xuan
*/
#define LOG_TAG "PhotoProcessing"
#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;
JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_PhotoProcessingActivity_grayPhoto
(JNIEnv *, jobject, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif
接着编写C代码
#include "PhotoProcessingActivity.h"
JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_PhotoProcessingActivity_grayPhoto(
JNIEnv *env, jobject photoProcessingActivity, jobject bmOriginal,
jobject bmGray) {
AndroidBitmapInfo origanalColor;
void* pixelscolor;
AndroidBitmapInfo infogray;
void* pixelsgray;
int ret;
int y;
int x;
LOGI("In convertToGray");
if ((ret = AndroidBitmap_getInfo(env, bmOriginal, &origanalColor)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
if ((ret = AndroidBitmap_getInfo(env, bmGray, &infogray)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
LOGI(
"original image :: width is %d; height is %d; stride is %d; format is %d;flags is %d,stride is %u", origanalColor.width, origanalColor.height, origanalColor.stride, origanalColor.format, origanalColor.flags, origanalColor.stride);
if (origanalColor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
LOGE("Bitmap format is not RGBA_8888 !");
//return;
}
if (origanalColor.format == ANDROID_BITMAP_FORMAT_RGB_565) {
LOGI("Original Image is ANDROID_BITMAP_FORMAT_RGB_565");
if ((ret = AndroidBitmap_lockPixels(env, bmOriginal, &pixelscolor))
< 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
if ((ret = AndroidBitmap_lockPixels(env, bmGray, &pixelsgray)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
// modify pixels with image processing algorithm
for (y = 0; y < origanalColor.height; y++) {
__uint16_t * line = (__uint16_t *) pixelscolor;
uint8_t * grayline = (uint8_t *) pixelsgray;
for (x = 0; x < origanalColor.width; x++) {
grayline[x] = (uint8_t)(((line[x] >> 11 <<3) + (line[x] >> 5 & 63 * 16) + (line[x]&31 * 8)) / 3);
//LOGI("%d %d %d %d",line[x].alpha,line[x].red,line[x].green,line[x].blue);
/*if(x ==0){
LOGI("line:%o grayline %o ",line[x],grayline[x]);
}*/
}
pixelscolor = (char *) pixelscolor + origanalColor.stride;
pixelsgray = (char *) pixelsgray + infogray.stride;
}
LOGI("unlocking pixels");
AndroidBitmap_unlockPixels(env, bmOriginal);
AndroidBitmap_unlockPixels(env, bmGray);
LOGI("Return !! ");
return ;
}
LOGI(
"gray image :: width is %d; height is %d; stride is %d; format is %d;flags is %d %d,stride is %u", infogray.width, infogray.height, infogray.stride, infogray.format, infogray.flags, infogray.stride);
if (infogray.format != ANDROID_BITMAP_FORMAT_A_8) {
LOGE("Bitmap format is not A_8 !");
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bmOriginal, &pixelscolor)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
if ((ret = AndroidBitmap_lockPixels(env, bmGray, &pixelsgray)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
// modify pixels with image processing algorithm
for (y = 0; y < origanalColor.height; y++) {
argb * line = (argb *) pixelscolor;
uint8_t * grayline = (uint8_t *) pixelsgray;
for (x = 0; x < origanalColor.width; x++) {
grayline[x] = (line[x].red + line[x].green + line[x].blue) / 3;
}
pixelscolor = (char *) pixelscolor + origanalColor.stride;
pixelsgray = (char *) pixelsgray + infogray.stride;
}
LOGI("unlocking pixels");
AndroidBitmap_unlockPixels(env, bmOriginal);
AndroidBitmap_unlockPixels(env, bmGray);
}
编写Android.mk文件,该文件主要是指明要使用的.so文件,并且生成我们自己的.so文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := PhotoProcessing
LOCAL_SRC_FILES := PhotoProcessing.cpp
LOCAL_LDLIBS := -llog -ljnigraphics
include $(BUILD_SHARED_LIBRARY)
关键的一些代码就是这些了,其中处理的灰度算法可能不是非常优化,这其中处理RGB565部分是我自己根据图像处理中灰度的定义所写的,其中也要感谢孙志海大哥对我的帮助 !!
可以说使用这种方法还是比较简易的,但是,似乎仍没解决我一开头说道的问题,即这种方式仅仅是提升了程序的效率,但依然需要在UI线程中更新界面,这里也可以使用SurfaceVIew来进行界面的更新,即可以在C线程中直接更新UI界面。
这里从最简单的显示图片开始,在SurfaceView上显示任意的内容,即我通过C代码获得SurfaceView的Surface后,在C程序中直接在Surface画内容,比如画绿色和画灰色,画完后便显示出来。
按钮监听
new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v("OnClick", "Onclick");
switch (v.getId()) {
case R.id.btGray:
Log.v("OnClick", "btGray");
grayPhoto(svHolder.getSurface());
break;
case R.id.btGreen:
showGreen(svHolder.getSurface());
break;
}
}
};
本地方法:
public native void grayPhoto(Surface surface);
public native void showGreen(Surface surface);
C代码
JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_SurfaceProcessingActivity_grayPhoto(
JNIEnv * env, jobject activity, jobject surface) {
ANativeWindow_Buffer nwBuffer;
LOGI("ANativeWindow_fromSurface ");
ANativeWindow * mANativeWindow = ANativeWindow_fromSurface(env, surface);
if (mANativeWindow == NULL) {
LOGE("ANativeWindow_fromSurface error");
return;
}
LOGI("ANativeWindow_lock ");
if (0 != ANativeWindow_lock(mANativeWindow, &nwBuffer, 0)) {
LOGE("ANativeWindow_lock error");
return;
}
LOGI("ANativeWindow_lock nwBuffer->format ");
if (nwBuffer.format == WINDOW_FORMAT_RGB_565) {
int y, x;
LOGI("nwBuffer->format == WINDOW_FORMAT_RGB_565");
__uint16_t * line = (__uint16_t *) nwBuffer.bits;
// modify pixels with image processing algorithm
for (y = 0; y < nwBuffer.height; y++) {
for (x = 0; x < nwBuffer.width; x++) {
//RGB565的灰色十进制为1280
line[x] = 57083;
}
line = line + nwBuffer.stride;
}
}
LOGI("ANativeWindow_unlockAndPost ");
if(0 !=ANativeWindow_unlockAndPost(mANativeWindow)){
LOGE("ANativeWindow_unlockAndPost error");
return;
}
ANativeWindow_release(mANativeWindow);
LOGI("ANativeWindow_release ");
}
有上面知道,可以在Surface上画任意内容,用来显示图片当然也是可以的,下一篇写如何使用libjpeg解析JPEG图片,并显示到SurfaceView上;
也许很多天没有都没能解决一个问题,但并不是没有收获,在学习的过程中所浏览的知识,所作的思考都会对自己以后的学习工作有巨大帮助的。