这次使用的场景是QQ好友下线后头像变黑白
使用了NDK中提供的位图解析接口
android\bitmap.h库中的三个接口 并且一共也是三个接口 至少到目前为止是三个
关于这个库的接口 点击查看android-ndk-r9d\android\bitmap.h
好友下线的效果图如下(图片尺寸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使用实例分析