android JNI处理图片的例子

原地址:http://blog.csdn.net/xjwangliang/article/details/7065670

<pre class="java" name="code">import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView; public class PhotoShop extends Activity {
private String tag = "IBMPhotoPhun";
private Bitmap bitmapOrig = null;
private Bitmap bitmapGray = null;
private Bitmap bitmapWip = null;
private ImageView ivDisplay = null;
// NDK STUFF
static {
try{
System.loadLibrary("haha");}
catch(Exception e) {
System.out.println("dd");
}
}
public native void convertToGray(Bitmap bitmapIn, Bitmap bitmapOut); public native void changeBrightness(int direction, Bitmap bitmap); public native void findEdges(Bitmap bitmapIn, Bitmap bitmapOut); // END NDK STUFF
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(tag, "before image stuff");
ivDisplay = (ImageView) findViewById(R.id.ivDisplay);
// load bitmap from resources
BitmapFactory.Options options = new BitmapFactory.Options();
// Make sure it is 24 bit color as our image processing algorithm
// expects this format
options.inPreferredConfig = Config.ARGB_8888;
bitmapOrig = BitmapFactory.decodeResource(this.getResources(),
R.drawable.sample, options);
if (bitmapOrig != null)
ivDisplay.setImageBitmap(bitmapOrig);
} public void onResetImage(View v) {
Log.i(tag, "onResetImage");
ivDisplay.setImageBitmap(bitmapOrig);
}
// 边缘化
public void onFindEdges(View v) {
Log.i(tag, "onFindEdges");
// make sure our target bitmaps are happy
bitmapGray = Bitmap.createBitmap(bitmapOrig.getWidth(),
bitmapOrig.getHeight(), Config.ALPHA_8);
bitmapWip = Bitmap.createBitmap(bitmapOrig.getWidth(),
bitmapOrig.getHeight(), Config.ALPHA_8);
// before finding edges, we need to convert this image to gray
convertToGray(bitmapOrig, bitmapGray);
// find edges in the image
findEdges(bitmapGray, bitmapWip);
ivDisplay.setImageBitmap(bitmapWip);
} public void onConvertToGray(View v) {
Log.i(tag, "onConvertToGray");
//创建一个和原图宽和高相等的灰色(一个像素是一个字节)图片,内容不确定或者为空(bitmapWip != null),就是说造好了格子只等填充数据
bitmapWip = Bitmap.createBitmap(bitmapOrig.getWidth(),
bitmapOrig.getHeight(), Config.ALPHA_8);
/**
* java中图片的config(相当于格式)
* ALPHA_8 (2),
RGB_565 (4),
ARGB_4444 (5),
ARGB_8888 (6);
与android不同:
ANDROID_BITMAP_FORMAT_RGBA_8888:1
ANDROID_BITMAP_FORMAT_A_8:8
*/
convertToGray(bitmapOrig, bitmapWip);
ivDisplay.setImageBitmap(bitmapWip);
}
//先要获得bitmapWip才能处理,否则setImageBitmap(byll)虽然不会报错,但是空白的
public void onDimmer(View v) {
Log.i(tag, "onDimmer");
changeBrightness(2, bitmapWip);
ivDisplay.setImageBitmap(bitmapWip);
}
//先要获得bitmapWip才能处理,否则setImageBitmap(byll)虽然不会报错,但是空白的
public void onBrighter(View v) {
Log.i(tag, "onBrighter");
changeBrightness(1, bitmapWip);
ivDisplay.setImageBitmap(bitmapWip);
}
} </pre><pre class="java" name="code">//下面是JNI层的代码</pre><pre class="java" name="code">//====================================================</pre><pre class="java" name="code">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
bitmapcolor:24位(实际是32)彩色图片;格式:ANDROID_BITMAP_FORMAT_RGBA_8888:
bitmapgray灰色图片(8位);格式:ANDROID_BITMAP_FORMAT_A_8
根据彩色图片填充灰色图片数据
*/
JNIEXPORT void JNICALL Java_com_msi_ibm_ndk_IBMPhotoPhun_convertToGray(JNIEnv
* env, jobject obj, jobject bitmapcolor,jobject bitmapgray)
{
AndroidBitmapInfo infocolor;//AndroidBitmapInfo图片信息
void* pixelscolor;//图片地址
AndroidBitmapInfo infogray;
void* pixelsgray;
int ret;
int y;
int x;
LOGI("convertToGray"); //AndroidBitmap_getInfo(env, bitmapcolor, &infocolor)得到图片信息
//AndroidBitmap_lockPixels(env, bitmapcolor, &pixelscolor)得到图片地址 if ((ret = AndroidBitmap_getInfo(env, bitmapcolor, &infocolor)) < 0) {//【AndroidBitmap_getInfo】没有图片信息(宽高等等)
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) {//不是24位图片
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) {//不是8位图片
LOGE("Bitmap format is not A_8 !");
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmapcolor, &pixelscolor)) < 0) {//【锁定AndroidBitmap_lockPixels】
//锁定之后,pixelscolor指向图片的首地址 
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
if ((ret = AndroidBitmap_lockPixels(env, bitmapgray, &pixelsgray)) < 0) {
//锁定之后,pixelscolor指向图片的首地址
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
// modify pixels with image processing algorithm
for (y=0;y<infocolor.height;y++) {//infocolor.height获得图片的高度
//这是首次使用argb
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);
}
/**
The AndroidBitmapInfo structure, defined in bitmap.h, is helpful for
learning about a Bitmap object. The AndroidBitmap_getInfo function, found in the jnigraphics library,
obtains information about a specific Bitmap object. a char represents a signed 8-bit value, so a char pointer (char *) allows you to reference an 8-bit
value and perform operations through that pointer. The image data is represented as uint8_t, which
means an unsigned 8-bit value, where each byte holds a value ranging from 0 to 255. A collection of
three 8-bit unsigned values represents a pixel of image data for a 24-bit image.
图象数据使用unit8_t(8位无符号,0-255),24-bit的图象就是3个8比特无符号数。 Working through an image involves working on the individual rows of data and
moving across the columns. The Bitmap structure contains a member known as the
stride. The stride represents the width, in bytes, of a row of image data. For
example, a 24-bit color plus alpha channel image has 32 bits, or 4 bytes, per pixel.
So an image with a width of 320 pixels has a stride of 320*4 or 1,280 bytes. An 8-bit
grayscale image has 8 bits, or 1 byte, per pixel. A grayscale bitmap with a width of
320 pixels has a stride of 320*1 or simply 320 bytes. With this information in mind,
let's look at the image processing algorithm for converting a color image to a
grayscale image:
Bitmap结构有一个属性stride(跨度):表示一行数据的长度。例如,24比特的图象每个像素有包含32位数据
(红绿蓝三种颜色,再加上alpha属性),所以宽度为320像素的图片的跨度(stride)为320*4字节。而rayscale
image每个像素只有8比特,就是一个字节,如果320像素,那么stride为320字节。 下面是原作者解释:
1. When the image data is "locked," the base address of the image data is
referenced by a pointer named pixelscolor for the input color image
and pixelsgray for the output grayscale image. 2. Two for-next loops allow you to iterate over the entire image. 1. First, you iterate over the height of the image, one pass per "row."
Use the infocolor.height value to get the count of the rows. 2. On each pass through the rows a pointer is set up to the memory
location corresponding to the first "column" of image data for the
row. 3. As you iterate over the columns for a particular row, you convert
each pixel of color data to a single value representing the
grayscale value. 4. When the complete row is converted you need to advance the
pointers to the next row. This is done by jumping forward in
memory by the stride value. */
/*
changeBrightness
Pixel Operation
改变亮度:direction=1表示增加亮度,direction=2减少亮度
bitmap只接受一个灰色图片(一个像素一个字节,格式ANDROID_BITMAP_FORMAT_A_8)
将灰色图片的像素值改变
*/
JNIEXPORT void JNICALL Java_com_msi_ibm_ndk_IBMPhotoPhun_changeBrightness(JNIEnv
* env, jobject obj, int direction,jobject bitmap)
{
AndroidBitmapInfo infogray;
void* pixelsgray;
int ret;
int y;
int x;
uint8_t save;//好像没有用到 //=======================
if ((ret = AndroidBitmap_getInfo(env, bitmap, &infogray)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
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, bitmap, &pixelsgray)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
// modify pixels with image processing algorithm
LOGI("time to modify pixels...."); for (y=0;y<infogray.height;y++) {//每个像素
uint8_t * grayline = (uint8_t *) pixelsgray;
int v;
for (x=0;x<infogray.width;x++) {
v = (int) grayline[x];
if (direction == 1)//与上面不同,灰色图片每个像素是一个字节,所以只需要改变一个字节
v -=5;
else
v += 5; if (v >= 255) {
grayline[x] = 255;
} else if (v <= 0) {
grayline[x] = 0;
} else {
grayline[x] = (uint8_t) v;
}
}
pixelsgray = (char *) pixelsgray + infogray.stride;
}
AndroidBitmap_unlockPixels(env, bitmap);
} /* /*
findEdges
Matrix operation
利用bitmapgray填充bitmapedges
*/
JNIEXPORT void JNICALL Java_com_msi_ibm_ndk_IBMPhotoPhun_findEdges(JNIEnv
* env, jobject obj, jobject bitmapgray,jobject bitmapedges)
{
AndroidBitmapInfo infogray;
void* pixelsgray;
AndroidBitmapInfo infoedges;
void* pixelsedge;
int ret;
int y;
int x;
int sumX,sumY,sum;
int i,j;
int Gx[3][3];
int Gy[3][3];
uint8_t *graydata;
uint8_t *edgedata; LOGI("findEdges running"); /**
[ -1 0 1 ]
Gx: [ -2 0 2 ]
[ -1 0 1 ] [ 1 2 1 ]
Gy: [ 0 0 0 ]
[ -1 -2 -1 ]
*/
Gx[0][0] = -1;Gx[0][1] = 0;Gx[0][2] = 1;
Gx[1][0] = -2;Gx[1][1] = 0;Gx[1][2] = 2;
Gx[2][0] = -1;Gx[2][1] = 0;Gx[2][2] = 1;
Gy[0][0] = 1;Gy[0][1] = 2;Gy[0][2] = 1;
Gy[1][0] = 0;Gy[1][1] = 0;Gy[1][2] = 0;
Gy[2][0] = -1;Gy[2][1] = -2;Gy[2][2] = -1; if ((ret = AndroidBitmap_getInfo(env, bitmapgray, &infogray)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
if ((ret = AndroidBitmap_getInfo(env, bitmapedges, &infoedges)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
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;
}
LOGI("color image :: width is %d; height is %d; stride is %d; format is %d;flags is
%d",infoedges.width,infoedges.height,infoedges.stride,infoedges.format,infoedges.flags);
if (infoedges.format != ANDROID_BITMAP_FORMAT_A_8) {
LOGE("Bitmap format is not A_8 !");
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmapgray, &pixelsgray)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
if ((ret = AndroidBitmap_lockPixels(env, bitmapedges, &pixelsedge)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
// modify pixels with image processing algorithm
LOGI("time to modify pixels...."); graydata = (uint8_t *) pixelsgray;
edgedata = (uint8_t *) pixelsedge; for (y=0;y<=infogray.height - 1;y++) {
for (x=0;x<infogray.width -1;x++) {
sumX = 0;
sumY = 0;
// check boundaries
if (y==0 || y == infogray.height-1) {
sum = 0;
} else if (x == 0 || x == infogray.width -1) {
sum = 0;
} else {
// calc X gradient
for (i=-1;i<=1;i++) {
for (j=-1;j<=1;j++) {
sumX += (int) ( (*(graydata + x + i + (y + j)* infogray.stride)) * Gx[i+1][j+1]);
}
}
// calc Y gradient
for (i=-1;i<=1;i++) {
for (j=-1;j<=1;j++) {
sumY += (int) ( (*(graydata + x + i + (y + j)* infogray.stride)) * Gy[i+1][j+1]);
}
}
sum = abs(sumX) + abs(sumY);
}
if (sum>255) sum = 255;
if (sum<0) sum = 0;
*(edgedata + x + y*infogray.width) = 255 - (uint8_t) sum;//给边界图片bitmapedges填充数据
}
}
AndroidBitmap_unlockPixels(env, bitmapgray);
AndroidBitmap_unlockPixels(env, bitmapedges);
</pre><pre class="java" name="code">}//结束</pre><br><img alt="" src="http://hi.csdn.net/attachment/201112/13/0_1323741853c9Ch.gif"><img alt="" src="http://hi.csdn.net/attachment/201112/13/0_1323741880F49S.gif"><br>

android JNI处理图片的例子的更多相关文章

  1. 一天掌握Android JNI本地编程 快速入门

    一.JNI(Java Native Interface)        1.什么是JNI:               JNI(Java Native Interface):java本地开发接口   ...

  2. 【转】android JNI

    原文网址:http://jinguo.iteye.com/blog/696185 Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码 ...

  3. android jni ——Field & Method --> Accessing Field

    现在我们知道了怎样使用native code访问简单的数据类型和引用参考类型(string,array),下面我们来介绍怎样让jni代码去访问java中的成员变量和成员函数,然后可以再jni中回调ja ...

  4. Android JNI开发提高篇

    有关JNI的开发技术,我们继续围绕Android平台进行,JNI可以支持C或C++,从目前为止我们写过的JNI代码均为C实现的,即文件名为.C而C++的和这些有什么不同呢? Android平台上的JN ...

  5. Android JNI(NDK)开发总结

    早就知道Java有个jni可以调用本地化代码,一直没有动力去研究它,现在公司想通过在Android中调用本地化代码来申请较多的内存以突破Android对单个进程的内存限制,这确实是可行的:我的Nexu ...

  6. android jni——helloworld

    看了网上好多牛人写的学习系列都是用HelloWorld作为开始,我们这里也用HelloWorld来开始我们的学习,首先我们来介绍下JNI吧. JNI作为java代码和C/C++的桥梁而存在的,为了让j ...

  7. Android JNI的Android.mk文件语法详解

    Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build System解 ...

  8. android JNI的.so库调用

    在一篇博客中看到一篇文章,感觉描述的还可以: 在前面的博客中介绍的都是使用java开发Android应用,这篇博客将介绍java通过使用jni调用c语言做开发 为了更加形象的介绍jni,先观察下面的图 ...

  9. Android JNI 数组操作

    JNI 中有两种数组操作,基础数据类型数组和对象数组,JNI 对待基础数据类型数组和对象数组是不一样的. 基本数据类型数组 对于基本数据类型数组,JNI 都有和 Java 相对应的结构,在使用起来和基 ...

随机推荐

  1. java list三种遍历方法性能比较

    从c/c++语言转向java开发,学习java语言list遍历的三种方法,顺便测试各种遍历方法的性能,测试方法为在ArrayList中插入1千万条记录,然后遍历ArrayList,发现了一个奇怪的现象 ...

  2. Java__jar包的简单操作

    工作需要研究了下jar,这里就举个简单的例子,以helloworld为例吧 1.启动eclipse编写代码: 次步不做赘述 package cn.test.jar; public class Hell ...

  3. Oracle成长点点滴滴(3)— 权限管理

    上篇我们解说了创建用户以及主要的授权问题.以下我们来解说权限包含对象权限和系统权限. 事实上上节课我们解说就是系统的权限.系统权限就是一些创建表了,表空间等等的系统的权限. 1.      系统权限 ...

  4. iPhone应用程序开发基础之一: IBOutlet与IBAction

    在图形界面编程时,解决的第一问题就是如何将静态界面与代码关联起来,或者说是代码如何与界面上的对象 通信, 代码如何操作界面上的对象.在iPhone平台上,引入了IBOutlet与IBAction.通过 ...

  5. service入门—电话监听器

    1.继承Service类 2.在清单文件进行配置(因为Service属于四大组件之一) <service android:name=".PhoneStatusService" ...

  6. 基于visual Studio2013解决C语言竞赛题之1016循环打印矩阵

         题目 解决代码及点评 /* 找规律,编程序打印6×6的矩阵: 1 2 3 5 8 13 1 4 9 17 30 51 1 6 19 45 92 173 . . . */ ...

  7. codeforces 148D 概率DP

    题意: 原来袋子里有w仅仅白鼠和b仅仅黑鼠 龙和王妃轮流从袋子里抓老鼠. 谁先抓到白色老师谁就赢. 王妃每次抓一仅仅老鼠,龙每次抓完一仅仅老鼠之后会有一仅仅老鼠跑出来. 每次抓老鼠和跑出来的老鼠都是随 ...

  8. Swift - iOS应用的国际化与本地化

    在Xcode中我们可以很方便的将APP适配各种本地化语言.苹果的框架已经帮我们把不同语言的数据分离开,包括图片,声音,视频,文档,用户界面文字(甚至代码中编写的用户界面文字),它们会被建立在同一个bu ...

  9. 来推荐个免费的PPT演示工具--ZohoShowTime

    事实上这个不算新产品了,这次是做了一些大的改进.上次在Zoho的全球用户大会上,全程演讲都是用的这个工具.Zoho这点非常好啊.自己的产品自己带头用.个人认为它最大的用处就是.离得远的观众能够在自己的 ...

  10. linux命令:echo

    echo $SHELL ----> /usr/bin/tcsh echo $ARBORDIR ----> /export/home/arbsfr/SFR_ENTREPRISE/SFRE3