说明
本文c代码来自于ndk demo。主要演示在ndk中如何操作bitmap对象,改变bitmap中的某些像素值。利用该功能再结合相应的算法,可实现将图片置灰等功能。
颜色
除了常用的rgb8888外,还有rgb565模式。
rgb565:用16位表示一个颜色,从高位到低位如下:R R R R R G G G G G G B B B B B。因此在该种模式下红色为0xf800,绿色为0x7e0,蓝色为0x1f。
基础
第一步:要导入#include <android/bitmap.h>头文件。
第二步:在ldLibs的值中加入"jnigraphics"。如下:
ndk {
moduleName "ImageJniUtils" //生成的so名字
ldLibs "log","jnigraphics" //可以使用log与graphics
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无
}
方法
AndroidBitmap_getInfo:获取一个AndroidBitmapInfo的结构体对象。利用该对象可以获取bitmap的format,height,width等信息。只有在该方法返回值>0的时才代表该方法执行成功。
AndroidBitmap_lockPixels:用于获取bitmap像素数组的地址。bitmap的每一个像素值都是一个int数值,它们存储在一个数组中(Bitmap#getPixels()会将这些数值存储到指定的数组中)。获取地址后就可以对每一个像素进行操作了。
AndroidBitmap_unlockPixels:与上面一个方法相反,它是释放地址。
示例
示例一:基本使用
void* pixels;
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) {
LOGE("Bitmap format is not RGB_565 !");
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {//此时pixels便指向了像素数组的首地址
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
/* Now fill the values with a nice little plasma */
fill_plasma(&info, pixels, time_ms );
AndroidBitmap_unlockPixels(env, bitmap);
对于pixels的使用如下(来自于置灰demo):
void *pixel = ((uint16_t *)pixels) + y * info.width + x;
uint16_t v = *(uint16_t *)pixel; //ARGB_565共16位,所以使用unit16_t
r = RGB565_R(v); //获取对应的r通道值
g = RGB565_G(v); //获取对应的g通道值
b = RGB565_B(v); //获取对应的b通道值
int gray = (r * 38 + g * 75 + b * 15) >> 7; //将获取到的三通道值改变
*((uint16_t *)pixel) = MAKE_RGB565(gray, gray, gray); //将改变后的值存储到原来的位置,这样就改变了这个位置上的像素值
示例二,微信红包图片
先将要保留的范围内的像素值单独存储,等图片模糊后再将范围内的像素值恢复。模糊代码的来源。如下:int Edge(int x, int y, int radius, int centerX, int centerY) {
return sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)) < radius &&
abs(y - centerY) <= radius && abs(x - centerX) <= radius;
}
JNIEXPORT void JNICALL Java_com_baigle_image_ImageUtils_blur(JNIEnv *env, jobject obj,
jobject bitmap, jint width,
jint height) {
AndroidBitmapInfo info;
void *pixels;
int ret;
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
return;
}
int centerX = info.width / 2;
int centerY = info.height / 3;
int shortP = info.width > info.height ? info.height : info.width;
int radius = shortP / 8;//确定保留半径
int x, y = centerY - radius;
void *dst = malloc((2 * radius + 1) * (2 * radius + 1) * sizeof(int));
for (; y <= centerY + radius; y++) {//保留像素值
for (x = centerX - radius; x <= centerX + radius; x++) {
if (Edge(x, y, radius, centerX, centerY)){
*((int *) dst + (y - centerY + radius) * (2 * radius + 1) + x - centerX +
radius) = *((int *) pixels + y * info.width + x);
}
}
}
blur((int *) pixels, info.width, info.height, 100);//调用模糊方法进行模糊
for (y = centerY - radius; y <= centerY + radius; y++) {//还原保留区域内的像素值
for (x = centerX - radius; x <= centerX + radius; x++) {
if (Edge(x, y, radius, centerX, centerY))
*((int *) pixels + y * info.width + x) = *((int *) dst + (y - centerY + radius) *
(2 * radius + 1) + x -
centerX + radius);
}
}
free(dst);
AndroidBitmap_unlockPixels(env, bitmap);
}
在使用图片时,将图片转换成ARGB_8888。如下:
mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.xxxxxxx);
mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888,false);