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

这次使用的场景是QQ好友下线后头像变黑白
使用了NDK中提供的位图解析接口
android\bitmap.h库中的三个接口 并且一共也是三个接口 至少到目前为止是三个
关于这个库的接口 点击查看android-ndk-r9d\android\bitmap.h

好友下线的效果图如下(图片尺寸900*675,位深度24)
图片为900*675(24位深度)

android部分代码
public class MainActivity extends Activity {

    private ImageView ivDisplay = null;
    private Bitmap bitmapOrig = null;
    private Bitmap bitmapGray = null;
    private Bitmap bitmapWip = null;

    static {
        System.loadLibrary("bitmapdemo");
    }

    public native void convertBmp(Bitmap bitmapIn, Bitmap bitmapOut);

    Boolean isColor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ivDisplay = (ImageView) findViewById(R.id.ivDisplay);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Config.ARGB_8888;
        bitmapOrig = BitmapFactory.decodeResource(this.getResources(),
                R.drawable.sampleimage, options);
        if (bitmapOrig != null)
            ivDisplay.setImageBitmap(bitmapOrig);
        isColor = true;
        bitmapWip = Bitmap.createBitmap(bitmapOrig.getWidth(),
                bitmapOrig.getHeight(), Config.ARGB_8888); 

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isColor){
                    isColor = false;
                    convertBmp(bitmapOrig, bitmapWip);
                    ivDisplay.setImageBitmap(bitmapWip);
                }else{
                    isColor = true;
                    ivDisplay.setImageBitmap(bitmapOrig);
                }
            }
        });
    }
}
jni部分代码
typedef struct 
{
    uint8_t alpha;
    uint8_t red;
    uint8_t green;
    uint8_t blue;
} argb;

/*
* convertToGray
* Pixel operation
*/
JNIEXPORT void JNICALL Java_com_example_bitmapdemo_MainActivity_convertBmp
    (JNIEnv * env, jobject  obj, 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;
    }

    void *srcBuf, *dstBuf;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, jsrcBitmap, &srcBuf)) {
        LOGE("lock src bitmap failed");
        return;
    }

    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, desBitmap, &dstBuf)) {
        LOGE("lock dst bitmap failed");
        return;
    }

    LOGI("width=%d; height=%d; stride=%d; format=%d;flag=%d",
            srcInfo.width, //  width=2700 (900*3)
            srcInfo.height, // height=2025 (675*3)
            srcInfo.stride, // stride=10800 (2700*4)
            srcInfo.format, // format=1 (ANDROID_BITMAP_FORMAT_RGBA_8888=1)
            srcInfo.flags); // flags=0 (ANDROID_BITMAP_RESULT_SUCCESS=0)

    int w = srcInfo.width;
    int h = srcInfo.height;
    int32_t *srcPixs = (int32_t *) srcBuf;
    int32_t *desPixs = (int32_t *) dstBuf;
    int alpha = 0xFF << 24;
    int i, j;
    int color;
    int red;
    int green;
    int blue;
    for (i = 0; i < h; i++) {
        for (j = 0; j < w; j++) {
            // get the color of per pixel 
            color = srcPixs[w * i + j];
            red = ((color & 0x00FF0000) >> 16);
            green = ((color & 0x0000FF00) >> 8);
            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);
}

主要通过AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr)对图片进行解码并获取解码后像素保存在内存中的地址指针addrPtr,通过对addrPtr指向的内存空间进行像素修改,就相当于直接修改了被加载到内存中的位图
调用AndroidBitmap_unlockPixels释放锁定 在内存中被修改的位图数据就可以用于显示到前台

这里的去彩色的计算方法就是把RGB三个颜色值平均即可,即是从白到黑的深浅程度的值
图片的RGB三个通道值如果一样颜色就是灰色的,通道的值越小越黑,越大越白
当RGB都是255就是白色。如果RGB都是0就是黑

这里获取到的跨距srcInfo.stride=10800=900*3*4 这里不对跨距进行展开讨论
可以学习yuv以及stride跨距的相关知识点进行了解

关于图片解码部分可以参考 libpng的png_read_info和png_read_image使用实例分析

点击查看完整例程源代码AndroidBitmapDemo

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在安卓JNI中,__FUNCTION__是一个预定义的宏,它可以返回当前函数的名称。它通常用于在调试或日志输出中显示当前函数的名称。在引用中,__FUNCTION__被用于显示正在执行的函数名称为AndroidRuntime::startVm。这个函数是用来启动虚拟机的,并且它的执行流程与sigchain_dummy不同,因此不会调用到sigchain_dummy这里。在引用中,__FUNCTION__没有被直接使用,但是在初始化操作的过程中,可能会使用其它函数来回调Java函数,并且使用__FUNCTION__来记录相关的日志信息。因此,__FUNCTION__主要是用来在日志或调试中标识当前函数的名称。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [安卓高版本c/c++调用java,通过JNI_CreateJavaVM/JNI_GetCreatedJavaVMs创建虚拟机实例](https://blog.csdn.net/zs787055144/article/details/131322208)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [JNI_OnLoad和JNI_OnUnload](https://blog.csdn.net/zhao007z5/article/details/80064818)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值