做过Java的同学可能经常会遇到一些关于图片处理的

例如类似QQ离线头像显示灰的。最快的算法是用colorMatrix来实现。这里通过Java调用JNI来处理每一个像素来实现。

  1. 对每一个像素点取出RGB每个通道的值R,G,B
  2. cololr=(R+G+B)/3;这个值是需要修改的值
  3. 将原来GRB的通道全设置成color的值

首先先看用Java怎么实现这个功能

 public Bitmap convertGrayImg(int resID)
{
Bitmap img1=((BitmapDrawable) getResources().getDrawable(resID)).getBitmap(); int w=img1.getWidth(),h=img1.getHeight();
int[] pix = new int[w * h];
img1.getPixels(pix, 0, w, 0, 0, w, h); int alpha=0xFF<<24;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
// 获得像素的颜色
int color = pix[w * i + j];
int red = ((color & 0x00FF0000) >> 16);
int green = ((color & 0x0000FF00) >> 8);
int blue = color & 0x000000FF;
color = (red + green + blue)/3;
color = alpha | (color << 16) | (color << 8) | color;
pix[w * i + j] = color;
}
}
Bitmap result=Bitmap.createBitmap(w, h, Config.RGB_565);
result.setPixels(pix, 0, w, 0, 0,w, h);
return result;
}

下面是JNI来处理

c++代码如下

#include <jni.h>
#include <string>
extern "C"{
jintArray JNICALL
Java_com_tmf_test_ndk_bitmap_MainActivity_getImgToGray(JNIEnv *env, jobject instance,
jintArray data_, jint w, jint h);
} JNIEXPORT jintArray JNICALL
Java_com_tmf_test_ndk_bitmap_MainActivity_getImgToGray(JNIEnv *env, jobject instance,
jintArray data_, jint w, jint h) {
jint *data;
data = env->GetIntArrayElements(data_, NULL);
if (data == NULL) {
return ; /* exception occurred */
}
int alpha = 0xFF << ;
for (int i = ; i < h; i++) {
for (int j = ; j < w; j++) {
// 获得像素的颜色
int color = data[w * i + j];
int red = ((color & 0x00FF0000) >> );
int green = ((color & 0x0000FF00) >> );
int blue = color & 0x000000FF;
color = (red + green + blue) / ;
color = alpha | (color << ) | (color << ) | color;
data[w * i + j] = color;
}
}
int size=w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result, , size, data);
env->ReleaseIntArrayElements(data_, data, );
return result;
}

activity实现如下

package com.tmf.test.ndk.bitmap;

import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView; public class MainActivity extends AppCompatActivity { // Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // Example of a call to a native method
ImageView tv = (ImageView) findViewById(R.id.image);
tv.setImageBitmap(getJniBitmap());
} public Bitmap getJniBitmap(){
Bitmap bitmap=((BitmapDrawable) getResources().getDrawable(R.mipmap.timg)).getBitmap();
int w=bitmap.getWidth(),h=bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
//通过ImgToGray.so把彩色像素转为灰度像素
int[] resultInt=getImgToGray(pix, w, h);
Bitmap resultImg=Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
resultImg.setPixels(resultInt, 0, w, 0, 0,w, h);
return resultImg;
} public native int[] getImgToGray(int[] data,int w,int h); private int[] bitmapToArray(int resID)
{
Bitmap bitmap=((BitmapDrawable) getResources().getDrawable(resID)).getBitmap();
int w=bitmap.getWidth(),h=bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
return pix;
} }

效果如下

bitmap.h

目录android-ndk-r10e\platforms\android-21\arch-arm\usr\include\android里面

bitmap.h头文件中的内容并不多,主要有这些部分组成:

  • 结果状态定义。
  • 位图格式枚举。
  • 位图信息结构体。
  • 位图操作函数声明。
define ANDROID_BITMAP_RESULT_SUCCESS
#define ANDROID_BITMAP_RESULT_BAD_PARAMETER -1
#define ANDROID_BITMAP_RESULT_JNI_EXCEPTION -2
#define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3 /* Backward compatibility: this macro used to be misspelled. */
#define ANDROID_BITMAP_RESUT_SUCCESS ANDROID_BITMAP_RESULT_SUCCESS

这里定义了对Bitmap进行操作时的结果,分别对应成功,错误的参数,JNI异常,内存分配错误,至于最后一个,这是个梗。Google工程师在定义NDK的时候写错一个单词,居然没有检查就发布了,然后就233333333了。看来IDE的拼写检查对自己人也有好处。

位图格式枚举

enum AndroidBitmapFormat {
ANDROID_BITMAP_FORMAT_NONE = ,
ANDROID_BITMAP_FORMAT_RGBA_8888 = ,
ANDROID_BITMAP_FORMAT_RGB_565 = ,
ANDROID_BITMAP_FORMAT_RGBA_4444 = ,
ANDROID_BITMAP_FORMAT_A_8 = ,
};

一般而言,常见的位图格式有RGB_565 、RGBA_8888、 ARGB_8888、 RGBA_4444、 ARGB_4444、 ALPHA_8

位图信息结构体

typedef struct {
uint32_t width;
uint32_t height;
uint32_t stride;
int32_t format;
uint32_t flags; // 0 for now
} AndroidBitmapInfo;

width表示图片的宽度(列数),height表示图片的高度(行数),stride为行跨度,具体含义后面会进行介绍。最后一个参数已经被弃用,其值始终为0。

位图操作函数声明

int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info); int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr); int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
  • AndroidBitmap_getInfo:获取当前位图信息。
  • AndroidBitmap_lockPixels:锁定当前位图像素,在锁定期间该Bitmap对象不会被回收,使用完成之后必须调用AndroidBitmap_unlockPixels函数来解除对像素的锁定。
  • AndroidBitmap_unlockPixels:解除像素锁定。
JNIEXPORT jboolean JNICALL
Java_com_tmf_test_ndk_bitmap_MainActivity_getImgToGray1(JNIEnv *env, jclass type, jobject jsrcBitmap,
jobject desBitmap) {
AndroidBitmapInfo srcInfo, dstInfo;
if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo(env, jsrcBitmap, &srcInfo)
|| ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo(env, desBitmap, &dstInfo)) {
LOGE("get bitmap info failed");
return false;
} void *srcBuf, *dstBuf;
if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, jsrcBitmap, &srcBuf)) {
LOGE("lock src bitmap failed");
return false;
} if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, desBitmap, &dstBuf)) {
LOGE("lock dst bitmap failed");
return false;
} int w = srcInfo.width;
int h = srcInfo.height;
int32_t *srcPixs = (int32_t *) srcBuf;
int32_t *desPixs = (int32_t *) dstBuf;
int alpha = 0xFF << 24;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
// 获得像素的颜色
int color = srcPixs[w * i + j];
int red = ((color & 0x00FF0000) >> 16);
int green = ((color & 0x0000FF00) >> 8);
int blue = color & 0x000000FF;
color = (red + green + blue) / 3;
color = alpha | (color << 16) | (color << 8) | color;
desPixs[w * i + j] = color;
}
}
AndroidBitmap_unlockPixels(env, jsrcBitmap);
AndroidBitmap_unlockPixels(env, desBitmap);
return true;
}

Java层代码

public  native boolean getImgToGray1(Bitmap src,Bitmap des);

效果和上面都一样的,只是这个直接在底层处理bitmap对象

如果有以下异常

  E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:52: undefined reference to `AndroidBitmap_getInfo'
E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:53: undefined reference to `AndroidBitmap_getInfo'
E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:59: undefined reference to `AndroidBitmap_lockPixels'
E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:64: undefined reference to `AndroidBitmap_lockPixels'
E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:86: undefined reference to `AndroidBitmap_unlockPixels'
E:\test\NdkBitmap\app\src\main\cpp/native-lib.cpp:87: undefined reference to `AndroidBitmap_unlockPixels'

我用的是Android studio自带的cmake打包的,需要在

在CMakeLists.txt 添加 -ljnigraphics

target_link_libraries( # Specifies the target library.
native-lib
-ljnigraphics
# Links the target library to the log library
# included in the NDK.
${log-lib} )

Android NDK开发 图片处理(五)的更多相关文章

  1. Android NDK开发初识

    神秘的Android NDK开发往往众多程序员感到兴奋,但又不知它为何物,由于近期开发应用时,为了是开发的.apk文件不被他人解读(反编译),查阅了很多资料,其中有提到使用NDK开发,怀着好奇的心理, ...

  2. Android NDK 开发(二) -- 从Hlello World学起【转】

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/41805719  上篇文章讲述了Android NDK开发的一些基本概念,以及NDK ...

  3. !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结

    http://hujiaweibujidao.github.io/blog/2013/11/18/android-ndk-and-opencv-development-3/ Android Ndk a ...

  4. Android NDK开发及OpenCV初步学习笔记

    https://www.jianshu.com/p/c29bb20908da Android NDK开发及OpenCV初步学习笔记 Super_圣代 关注 2017.08.19 00:55* 字数 6 ...

  5. android NDK开发在本地C/C++源码中设置断点单步调试具体教程

    近期在学android NDK开发,折腾了一天,最终可以成功在ADT中设置断点单步调试本地C/C++源码了.网上关于这方面的资料太少了,并且大都不全,并且调试过程中会出现各种各样的问题,真是非常磨人. ...

  6. windows下用ADT进行android NDK开发的具体教程(从环境搭建、配置到编译全过程)

    郑重申明:如需转载本博客,请注明出处,谢谢! 这几天在学习android NDK的开发.那么首先让我们来看看android NDK开发的本质是什么. NDK(Native Development Ki ...

  7. Android NDK开发Hello Word!

    在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...

  8. Android NDK开发

    Android NDK 开发教程(极客学院) 一.Android NDK环境搭建 使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin( ...

  9. Android NDK 开发(四)java传递数据到C【转】

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/41845701 前面几篇文章介绍了Android NDK开发的简单概念.常见错误及处 ...

随机推荐

  1. Json Post到 https的坑 - the underlying connection was closed an unexpected error occurred on a send(远程服务器未知错误导致关闭)

    最近做了一个安装包,安装包会弹出dotnet的 窗体,这个安装包会去调用https的一个api.用测试程序测试窗体都是好的.一旦打入安装包后,就报错.研究了半天,原来是https惹的祸 解决方案: . ...

  2. IDEA工作中常用快捷键

    ctrl+shift+t: Ubuntu中在一个工具栏中打开两个终端 shift+shift: 搜索任何类 ctrl+N: 搜索任何类 ctrl+right: forward----自定义 ctrl+ ...

  3. Mac安装破解版Office 2016办公软件

    一.相关软件 Microsoft Office 2016 For Mac Cracker 破解工具 资源地址(链接:https://pan.baidu.com/s/1Z5CIv-XbxS08MniYN ...

  4. 小小c#算法题 - 7 - 堆排序 (Heap Sort)

    在讨论堆排序之前,我们先来讨论一下另外一种排序算法——插入排序.插入排序的逻辑相当简单,先遍历一遍数组找到最小值,然后将这个最小值跟第一个元素交换.然后遍历第一个元素之后的n-1个元素,得到这n-1个 ...

  5. [译]Javascript中的Ternary operator

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  6. oracle数据库性能

    性能视图V$开头 V$SYSTEM_EVENT 正在等待的资源的系统信息 V$SESSION_EVENT 会话累计发生的等待事件 V$SESSION_WAIT 会话正在等待或者曾经等待的详细时间信息 ...

  7. City Game UVALive - 3029(悬线法求最大子矩阵)

    题意:多组数据(国外题好像都这样),每次n*m矩形,F表示空地,R表示障碍 求最大子矩阵(悬线法模板) 把每个格子向上延伸的空格看做一条悬线 以le[i][j],re[i][j],up[i][j]分别 ...

  8. 使用原生js来操作对象dom的class属性

    之前一直都使用jquery来操作dom,今天想自己用原生写一些插件,却发现给dom增删class的时候,使用slice来截取className特别的麻烦,后来发现,原来原生JS本来就有提供api来对d ...

  9. NSFileManager在初始化文件的时候一不留神就进入陷阱

    今天调试一个程序,内容是在手机一个本地路径生成一个缓存文件,在生成本地路径的时候犯了一个错误,本着求原因的精神调试了2个小时,终于找到原因了 刚开始断点调试的时候,执行到第13行,这里死活不给写入数据 ...

  10. 洛谷 P1801 黑匣子_NOI导刊2010提高(06)

    题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个Black Box要处理一串命令. 命令只有两种: ...