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

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

好友下线的效果图如下(图片尺寸900*675,位深度24)
JNI下使用AndroidBitmap_lockPixels修改位图为黑白照片_第1张图片

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

你可能感兴趣的:(安卓中使用JNI编程)