前言
由于有一个demo中需要将存有ARGB数据的byte[]显示出来,首先我想到的是转Bitmap。在网上找了一些方法,比如使用BitmapFactory.decodeByteArray()方法直接转换,或者先转成流再读到Bitmap中。但是神奇的是,这两种方法转出来的Bitmap对象都是null对象。
后来我在去百度了一下,发现有人说BitmapFactory.decodeByteArray()方法是用来从YUV读入数据的(我还没尝试过)。如果让我将ARGB转成YUV420的话,感觉就有些繁琐了。后来我寻思着是不是直接在Native层进行转换,顺便学习一下Bitmap的Native操作。
参考文章为:
https://www.jianshu.com/p/8efb655d9305
代码
下面开始讲解如何在Native层将存有ARGB数据的byte[]存入bitmap。
- 1.需要在JAVA层建一个Bitmap,格式为ARGB:(在native也可以创建Bitmap,但是代码就不止一行了)
Bitmap img_result = Bitmap.createBitmap(im_w,im_h,Bitmap.Config.ARGB_8888);
- 2.在JAVA层写一个native接口:
public native void bytearray2bitmap_argb(byte[] byte_scr,Bitmap bitmap_dst);
- 3.在Native层写一个对应的接口:
JNIEXPORT void JNICALL _Function(bytearray2bitmap_1argb)(JNIEnv *env, jobject /* this */,jbyteArray byte_scr,jobject bitmap_dst)
{
};
- 4.写Native实现代码:
jboolean inputCopy = JNI_FALSE;
// 取出byte[]的指针
uint8_t* byte_scr_ptr = reinterpret_cast<uint8_t*>(env->GetByteArrayElements(byte_scr, &inputCopy));
// 读取 bitmap 的信息
AndroidBitmapInfo bitmapInfo;
int ret;
if ((ret = AndroidBitmap_getInfo(env, bitmap_dst, &bitmapInfo)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
// 读取 bitmap 到 native 内存,并返回指针
void *bitmapPixels;
if ((ret = AndroidBitmap_lockPixels(env, bitmap_dst, &bitmapPixels)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
return;
}
// 读取bitmap的大小
uint32_t newWidth = bitmapInfo.width;
uint32_t newHeight = bitmapInfo.height;
int32_t type = bitmapInfo.format;
LOGE("newWidth=%i newHeight=%i type=%i",newWidth,newHeight,type);
// 32位输入方式和8位输入方式结果相同
// 载入byte[]到bitmap 32位输入
uint32_t *bitmap_ptr = (uint32_t *) bitmapPixels;
for (int r = 0; r < newHeight; ++r) {
for (int c =0; c < newWidth; ++c) {
uint32_t pixel=0;
pixel = pixel | ((uint32_t)*(byte_scr_ptr + (r*newWidth+c)*4 + 0) & 0xff); // a
pixel = pixel<< 8 | ((uint32_t)*(byte_scr_ptr + (r*newWidth+c)*4 + 3) & 0xff ); // b
pixel = pixel<< 8 | ((uint32_t)*(byte_scr_ptr + (r*newWidth+c)*4 + 2) & 0xff ); // g
pixel = pixel<< 8 | ((uint32_t)*(byte_scr_ptr + (r*newWidth+c)*4 + 1) & 0xff ); // r
*(bitmap_ptr+r*newWidth+c)=pixel;
}
}
// 载入byte[]到bitmap 8位输入
uchar *bitmap_ptr = (uchar *) bitmapPixels;
for (int r = 0; r < newHeight; ++r) {
for (int c =0; c < newWidth; ++c) {
*(bitmap_ptr + 4*(r*newWidth+c) + 0)=*(byte_scr_ptr + (r*newWidth+c)*4 + 1); // r
*(bitmap_ptr + 4*(r*newWidth+c) + 1)=*(byte_scr_ptr + (r*newWidth+c)*4 + 2); // g
*(bitmap_ptr + 4*(r*newWidth+c) + 2)=*(byte_scr_ptr + (r*newWidth+c)*4 + 3); // b
*(bitmap_ptr + 4*(r*newWidth+c) + 3)=*(byte_scr_ptr + (r*newWidth+c)*4 + 0); // a
}
}
// 释放,供java继续使用
AndroidBitmap_unlockPixels(env, bitmap_dst);
env->ReleaseByteArrayElements(byte_scr, (jbyte*)byte_scr_ptr, 0);
其中我的LOGE写法:
#include <android/log.h>
#define LOG_TAG "in native "
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
大功告成。
如果有什么错误欢迎指出。