在Native层完成byte[]转bitmap

前言

由于有一个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__)

大功告成。

如果有什么错误欢迎指出。

猜你喜欢

转载自blog.csdn.net/qq_19313495/article/details/98186031