做过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. 2019年第十届蓝桥杯省赛总结(JavaA组)

    //update3.28:省一rank4,莫名进了国赛好神奇.. 记yzm10第一次体验A组(纯粹瞎水). 早闻山东的JavaA组神仙打架,进国赛都成了奢望(往年只有五个名额),因此抱着做分母的心态来 ...

  2. ASP.NET常用数据绑定控件优劣总结

    本文的初衷在于对Asp.net常用数据绑定控件进行一个概览性的总结,主要分析各种数据绑定控件各自的优缺点,以便在实际的开发中选用合适的控件进行数据绑定,以提高开发效率. 因为这些数据绑定控件大部分都已 ...

  3. c# 捕获非托管异常

    在.NET 4.0之后,CLR将会区别出一些异常(都是SEH异常),将这些异常标识为破坏性异常(Corrupted State Exception).针对这些异常,CLR的catch块不会捕捉这些异常 ...

  4. 【转】 robotframework(rf)中对时间操作的datetime库常用关键字

    转自http://blog.csdn.net/r455678/article/details/52993765 DateTime库是robotframework内置的库 1.对固定日期进行操作,增加或 ...

  5. Python3中简单的迭代器程序

    1.迭代器程序(实现菲比那次数列并且可以抛出与接收异常) def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a,b = b ...

  6. Python3的简单的函数调用

    python3的几种传参方法(初学者): 例1: def func(x,*argv): print(x) print(argv) func('alex','wt','hjc','lao liu') 输 ...

  7. 算法训练 Pollution Solution(计算几何)

    问题描述 作为水污染管理部门的一名雇员,你需要监控那些被有意无意倒入河流.湖泊和海洋的污染物.你的其中一项工作就是估计污染物对不同的水生态系统(珊瑚礁.产卵地等等)造成的影响. 你计算所使用的模型已经 ...

  8. 【转】tnsping不通,则需设置TNS_ADMIN环境变量

    源地址:http://blog.csdn.net/pan_tian/article/details/7699599

  9. shell参数位置

    1给脚本文件传参 #!/bin/bash echo "a $1" echo "b $2" 执行传参: $ ../test.sh a b 输出结果: a a b ...

  10. Web安全工程师(进阶)课程表

    01-SQL注入漏洞原理与利用 预备知识: 了解HTTP协议,了解常见的数据库.脚本语言.中间件.具备基本的编程语言基础. 授课大纲: 第一章:SQL注入基础 1.1 Web应用架构分析1.2 SQL ...