接上一篇,上一篇讲了jni的一些基本知识,可能大家都很懵逼,这很正常,在这里,我们将以一个简单的小实例,继续探索jni的使用,没有看上一篇博客的可以先看上一篇哦,附上链接: jni开发:jni基础教程及实例(一),当然,如果你对jni已经有了基本的了解,可以跳过上一篇博客,废话不说,我们进入正题。
我们写一个demo,将一张res下的彩色图片转换为黑白图片,功能还是很简单的,简单粗暴,直接上代码:
1.首先是布局文件,一个Button,两个ImageView,so easy,这里不再赘述:
2.接着,我们在MainAvtivity里面添加如下代码:
package com.example.admin.jnitestbitmapdemo;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private ImageView mImg1, mImg2;
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImg1 = (ImageView) findViewById(R.id.iv1);
mImg2 = (ImageView) findViewById(R.id.iv2);
btn = (Button) findViewById(R.id.change);
btn.setOnClickListener(this);
mImg1.setImageResource(R.mipmap.test2);
// Example of a call to a native method
}
/**
* 从assets中加载图片
* @return
*/
private Bitmap loadBitmap() {
Bitmap bmp = null;
AssetManager am = getResources().getAssets();
try {
InputStream is = am.open("test2.jpg");
BitmapFactory.Options options = new BitmapFactory.Options();
bmp = BitmapFactory.decodeStream(is ,null , options);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return bmp;
}
/**
* 处理图片,此方法中会调用nativeProcessBitmap
* @param bitmap
* @return
*/
private Bitmap processBitmap(Bitmap bitmap) {
Bitmap bmp = bitmap.copy(Bitmap.Config.ARGB_8888, true);
nativeProcessBitmap( bmp);
return bmp;
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native void nativeProcessBitmap(Bitmap bitmap);
@Override
public void onClick(View view) {
Bitmap originalBitmap = loadBitmap();
Bitmap resultBitmap = processBitmap(originalBitmap);
mImg2.setImageBitmap(resultBitmap);
}
}
可以看到,使用jni之前,需要调用System.loadLibrary导入,而jni里的方法都是native在前的
3.现在进入我们的jni部分
#include
#include
#include
#include
#ifndef eprintf
#define eprintf(...) __android_log_print(ANDROID_LOG_ERROR,"@",__VA_ARGS__)
#endif
#define MAKE_RGB565(r,g,b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))
#define MAKE_ARGB(a,r,g,b) ((a&0xff)<<24) | ((r&0xff)<<16) | ((g&0xff)<<8) | (b&0xff)
#define RGB565_R(p) ((((p) & 0xF800) >> 11) << 3)
#define RGB565_G(p) ((((p) & 0x7E0 ) >> 5) << 2)
#define RGB565_B(p) ( ((p) & 0x1F ) << 3)
#define RGB8888_A(p) (p & (0xff<<24) >> 24 )
#define RGB8888_R(p) (p & (0xff<<16) >> 16 )
#define RGB8888_G(p) (p & (0xff<<8) >> 8 )
#define RGB8888_B(p) (p & (0xff) )
extern "C" JNIEXPORT jstring
JNICALL
Java_com_example_admin_jnitestbitmapdemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_admin_jnitestbitmapdemo_MainActivity_nativeProcessBitmap(JNIEnv *env,
jobject instance,
jobject bitmap) {
// TODO
if (bitmap == NULL) {
eprintf("bitmap is null\n");
return;
}
/*
* 通过bitmap获得AndroidBitmapInfo对象,AndroidBitmapInfo为我们提供了Bitmap的所有信息
*/
AndroidBitmapInfo bitmapInfo;
memset(&bitmapInfo , 0 , sizeof(bitmapInfo));
AndroidBitmap_getInfo(env , bitmap , &bitmapInfo);
//获得bitmap的像素矩阵,并将它存放在&pixels中
void * pixels = NULL;
int res = AndroidBitmap_lockPixels(env, bitmap, &pixels);
int x = 0, y = 0;
for (y = 0; y < bitmapInfo.height; ++y) {
// From left to right
for (x = 0; x < bitmapInfo.width; ++x) {
int a = 0, r = 0, g = 0, b = 0;
void *pixel = NULL;
// Get each pixel by format
if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888)
{
pixel = ((uint32_t *)pixels) + y * bitmapInfo.width + x;
int r,g,b;
uint32_t v = *((uint32_t *)pixel);
r = RGB8888_R(v);
g = RGB8888_G(v);
b = RGB8888_B(v);
int sum = r+g+b;
*((uint32_t *)pixel) = MAKE_ARGB(0x1f , sum/3, sum/3, sum/3);
}
else if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565) {
pixel = ((uint16_t *)pixels) + y * bitmapInfo.width + x;
int r,g,b;
uint16_t v = *((uint16_t *)pixel);
r = RGB565_R(v);
g = RGB565_G(v);
b = RGB565_B(v);
int sum = r+g+b;
*((uint16_t *)pixel) = MAKE_RGB565(sum/3, sum/3, sum/3); }
}
}
//解锁
AndroidBitmap_unlockPixels(env, bitmap);
}
在这里面,有两个方法,第一个是我们使用Andoid Studio配置ndk的时候自动生成的,当它可能被调用成功时,说明jni环境已配置好,可以开始做jni开发了,我们在这里用的是第二个方法,它将传进来的bitmap转换为灰度图。
4.最后是导入图片,这个太简单咯,自己任意导入一张即可,我们来看看最后的效果:
这就是jni的使用,当然,实际开发中,通常我们会在jni里面调用算法so库里的函数,比这个要复杂,不过理解了这个后,jni的开发算是有了基本的理解了
附上demo的下载地址:jni转换为灰度图demo