做过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. html 连接数据库

    http://blog.csdn.net/haxker/article/details/4214001 http://www.cnblogs.com/chuncn/archive/2010/11/22 ...

  2. Spring JDBCTemplate配置使用

    一.开发环境 Windows 10 IntelliJ IDEA 2016.1 旗舰版 JDK1.8 二.项目和数据库结构 项目结构: 数据库(MySQL 5.5.39): /* Navicat MyS ...

  3. [转]MYSQL5.7版本sql_mode=only_full_group_by问题

    转至:https://www.cnblogs.com/zhi-leaf/p/5998820.html 具体出错提示: [Err] 1055 - Expression #1 of ORDER BY cl ...

  4. jquery ajax 分页

    <script src="../Js/jQuery/jquery-1.8.2.min.js" type="text/javascript">< ...

  5. web 打印分页技巧

     page-break-after 和 page-break-before: page-break-before和page-break-after CSS属性并不会修改网页在屏幕上的显示,这两个属性是 ...

  6. webservice服务及客户端 编程 - 入门

    开发工具 eclipse 建立一个简单的webservice服务 1 创建服务 (1)创建一个 java项目(java project)或 web项目(Dynamic web project) (2) ...

  7. Binder学习笔记(二)——defaultServiceManager()返回了什么?

    不管是客户端还是服务端,头部都要先调用 sp < IServiceManager > sm = defaultServiceManager(); defaultServiceManager ...

  8. flink学习笔记-快速生成Flink项目

    说明:本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKh ...

  9. [WebShow系列] 需求及环境的确定

    需求及环境确定: 主题标语 选手人数 评委人数 打分方式 合计算法 名次算法 大屏数量 大屏分辨率 电脑配置 切换设备 评委人员配备 技术人员配备 现场网速情况 评委移动端配备 场次数量 场次时间 选 ...

  10. sublime侧边栏管理sidebarEnhancements浏览器设置

    sidebarEnhancements是为了增强sublime Text侧边栏功能的一个插件,但是同时也可以实现设置浏览器浏览当前文件的功能. Ctrl+Shift+p 输入package contr ...