Android JNI操作Bitmap实现黑白图片

最近想练习一下NDK,基于我接下来的目标是多媒体,多以想多点学习一下关于滤镜的知识,黑白滤镜是最简单的了。

这里实现的是将一张彩色图片转成黑白图片,是黑白滤镜的基础!

直接上码:

// java 代码
public void gray(View view) {
    Bitmap source = BitmapFactory.decodeResource(getResources(), R.drawable.time);
    Bitmap target = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
    BitmapTools.gray(source, target);
    targetView.setImageBitmap(target);
}
// c 代码
#include <jni.h>
#include <android/bitmap.h>
#include <android/log.h>

#define TAG "bitmap-lib"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG ,__VA_ARGS__)

extern "C"
JNIEXPORT void JNICALL
Java_com_johan_ndk_BitmapTools_gray(JNIEnv *env, jobject obj, jobject source, jobject target) {
    int result;
    // 获取源Bitmap相关信息:宽、高等
    AndroidBitmapInfo sourceInfo;
    result = AndroidBitmap_getInfo(env, source, &sourceInfo);
    if (result < 0) {
        LOGE("get bitmap info error : %d", result);
        return;
    }
    // 获取源Bitmap像素数据 这里用的是32位的int类型 argb每个8位
    uint32_t *sourceData;
    result = AndroidBitmap_lockPixels(env, source, (void**) &sourceData);
    if (result < 0) {
        LOGE("bitmap lock pixels error : %d", result);
        return;
    }
    // 锁定Bitmap 
    // 并获取目标Bitmap像素数据 
    // 注意:传进来的Bitmap只是一张空的Bitmap
    uint32_t *targetData;
    result = AndroidBitmap_lockPixels(env, target, (void**) &targetData);
    if (result < 0) {
        LOGE("bitmap lock pixels error : %d", result);
        return;
    }
    // 遍历各个像素点
    int color;
    int alpha = 0xff << 24;
    int red, green, blue;
    int width = sourceInfo.width;
    int height = sourceInfo.height;
    int w, h;
    for (h = 0; h < height; h++) {
        for (w = 0; w < width; w++) {
            color = sourceData[h*width+w];
            red = (color & 0x00ff0000) >> 16;
            green = (color & 0x0000ff00) >> 8;
            blue = color & 0x000000ff;
            // rgb颜色相同就是黑白图片了 取平均值只是一个方案
            color = (red + green + blue) / 3;
            targetData[h*width+w] = alpha | (color << 16) | (color << 8) | color;
        }
    }
    AndroidBitmap_unlockPixels(env, source);
    AndroidBitmap_unlockPixels(env, target);
}

注意Cmake文件要添加库,否则会报找不到 AndroidBitmap_getInfo 等Bitmap方法:

target_link_libraries( 
                       ...
                       jnigraphics
 )

效果:

以上是我仿 这篇博文 写的,但是我看到这篇博文有一条评论,说是像素点在c上存在大小端的问题,于是乎我改了一点代码:

...
for (h = 0; h < height; h++) {
    for (w = 0; w < width; w++) {
        color = sourceData[h*width+w];
        red = (color & 0x00ff0000) >> 16;
        green = (color & 0x0000ff00) >> 8;
        blue = color & 0x000000ff;
        blue += 60;
        if (blue > 255) {
            blue = 255;
        }
        color = (red + green + blue) / 3;
        targetData[h*width+w] = alpha | (red << 16) | (green << 8) | blue;
    }
}
...

这样改之后,界面应该偏冷色,结果却是:

居然是暖色调了,证明的确存在大小端的问题,所以在C层中,Bitmap像素点的值是BGR,而不是RGB,也就是说,高端到低端:B,G,R!所以代码得改一下:

...
for (h = 0; h < height; h++) {
    for (w = 0; w < width; w++) {
        color = sourceData[h*width+w];
        blue = (color & 0x00ff0000) >> 16;
        green = (color & 0x0000ff00) >> 8;
        red = color & 0x000000ff;
        blue += 80;
        if (blue > 255) {
            blue = 255;
        }
        color = (red + green + blue) / 3;
        targetData[h*width+w] = alpha | (blue << 16) | (green << 8) | red;
    }
}
...

这样改了之后,结果就正常为冷色调了:

至于黑白时没有高低端问题呢,是因为color去的是rgb的平均值,所以不论是r+g+b,还是b+g+r,值都是一样!!

通过这个例子,不仅复习了一下NDK操作,而且还知道了Bitmap像素点存在高低端问题!!值了~

参考资料

JNI下使用AndroidBitmap_lockPixels修改位图为黑白照片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值