jni与bitmap

说明

        本文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);





你可能感兴趣的:(jni与bitmap)